Skip to content

Open Closed Principle

Subrata Sahoo edited this page Jul 19, 2024 · 4 revisions

Objects or entities should be open for extension but closed for modification.

What does it mean?

It means that the behaviour of a module should be extendable without modifying its source code.

Advantages

  • Enhance Maintainability: Not modifying existing code reduces the risk of introducing new bugs.
  • Encourage Code Reusability: Adding new functionality through extension, can often be reused in different parts of the application.
  • Facilitate Scalability: Systems designed with OCP in mind can be more easily scaled. New features and changes can be integrated without altering the core functionality, making the system more adaptable to future requirements.
  • Promote Clear Design and Architecture: Following OCP often leads to a design that clearly separates concerns. This makes the architecture of the system more understandable and easier to manage.
  • Improve Testing: Since existing code is not modified, existing tests for that code remain valid. New functionality can be tested independently of the existing code.

Pitfalls

Problem Description Solution
Complexity of Abstractions Need of defining abstractions (e.g., interfaces or abstract classes). Designing these abstractions can be complex and may require significant upfront effort. Ensure that abstractions are well-thought-out and truly necessary. Use proven design patterns and practices to create meaningful and reusable abstractions.
Overuse of Abstractions Applying OCP can sometimes lead to an overabundance of abstractions, which may make the codebase harder to understand and maintain. Use abstractions judiciously. Avoid creating excessive layers of indirection that add complexity without providing substantial benefits.
Difficulty in Identifying Extension Points Determining where and how to extend functionality can be challenging. Misidentifying extension points may lead to designs that are either too rigid or too flexible. Invest time in understanding the domain and requirements to accurately identify appropriate extension points. Regularly review and refactor the design as needed.
Increased Design and Development Time Designing systems to be open for extension may require more upfront design work and longer development time. Balance the need for extensibility with project timelines and requirements. Focus on areas where extensibility will provide significant long-term benefits.
Potential for Over-Engineering Striving to adhere to OCP may lead to over-engineering, where the system becomes overly complex with unnecessary abstractions and extensibility mechanisms. Ensure that extensions are practical and necessary. Avoid adding complexity for the sake of adhering to OCP if it doesn’t align with the system’s needs.
Testing Challenges While OCP aims to make code more maintainable, it can sometimes complicate testing, especially if new extensions are not well-integrated or if abstractions are misused. Develop comprehensive test plans that account for both existing functionality and new extensions. Use mocking and dependency injection to test components in isolation.
Inconsistent Use of Patterns Inconsistent application of design patterns and principles related to OCP can lead to a fragmented design, where some parts of the system adhere to OCP while others do not. Establish and enforce design guidelines and best practices for using patterns and principles consistently across the codebase.
Performance Overheads Introducing abstractions and indirection to support extensibility can sometimes introduce performance overheads or affect efficiency. Profile and monitor performance to ensure that abstractions do not negatively impact critical parts of the system. Optimize where necessary without compromising the design principles.

Example Explained

The PaymentProcessor class in WithOutOCP folder handles different payment methods directly, which means modifying the class whenever a new payment method is added. This violates the open/closed principle.

To adhere to the Open/Closed Principle, we introduce an abstraction for the payment method and extend the system by adding new payment methods without modifying the existing code.

In the refactored example in the WithOCP folder:

  • The IPaymentMethod interface defines a contract for payment processing.
  • CreditCardPayment, PayPalPayment, and BitcoinPayment are concrete implementations of the IPaymentMethod interface.
  • The PaymentProcessor class depends on the IPaymentMethod interface, allowing it to process any payment method that implements this interface.

To add a new payment method, we simply create a new class that implements the IPaymentMethod interface without modifying the existing PaymentProcessor class, thus adhering to the Open/Closed Principle.

Clone this wiki locally