-
Open Closed Principle
-
The Open/Closed Principle (OCP) is one of the SOLID principles of object-oriented design, emphasizing that "software entities such as classes, modules, functions, etc… should be open for extension but closed for modification". This means that you should be able to extend the behaviour of a system without modifying its existing codebase.
Understanding the Open/Closed Principle (OCP)- Open for extension: This means that you should be able to add new functionality to your system without changing the existing code base.
- Closed for modification: Once a class (or module) is written and tested, it should not be changed except to correct bugs. Its existing functionality should remain intact.
In Simple words, New features should be implemented using the new code, not by changing existing code. Adhering to OCP potentially streamlines code maintenance and reduces the risk of breaking the existing implementation. Lets check this with an example.
Examples of OCP in C#
Bad Example (Violation of OCP)
Scenario:Consider a banking application where we have a class responsible for calculating interest rates based on different account types. Initially, we have savings and checking accounts.
Initial Implementation
public class InterestCalculator { public double CalculateInterest(Account account) { if (account.Type == AccountType.Savings) { return account.Balance * 0.03; // 3% interest rate for savings accounts } else if (account.Type == AccountType.Checking) { return account.Balance * 0.01; // 1% interest rate for checking accounts } return 0; } }
Now, suppose we need to add a new type of account, like a Money Market account. According to the Open/Closed Principle, we should extend rather than modify existing code. However, in this case, we would need to modify the InterestCalculator class to accommodate the new account type.
public double CalculateInterest(Account account) { if (account.Type == AccountType.Savings) { return account.Balance * 0.03; } else if (account.Type == AccountType.Checking) { return account.Balance * 0.01; } else if (account.Type == AccountType.MoneyMarket) { return account.Balance * 0.05; // New 5% interest rate for Money Market accounts } return 0; }
In this case:
- The InterestCalculator violates the OCP because it is not closed for modification; we had to change its code to accommodate the new MoneyMarketaccount type.
- This approach can lead to fragile code and potential bugs, especially if there are multiple places where interest rates are calculated based on account types.
Scenario:Let's say we have a system that calculates shipping costs based on different shipping methods. Initially, the system supports two methods: Standard Shipping and Express Shipping.
Implementation:
// Abstract base class representing a shipping method public abstract class ShippingMethod { public abstract double CalculateShippingCost(double orderTotal); } // Concrete class for Standard Shipping public class StandardShipping : ShippingMethod { public override double CalculateShippingCost(double orderTotal) { // Standard shipping cost calculation logic return orderTotal * 0.05; // 5% of order total } } // Concrete class for Express Shipping public class ExpressShipping : ShippingMethod { public override double CalculateShippingCost(double orderTotal) { // Express shipping cost calculation logic return orderTotal * 0.1; // 10% of order total } }
Now, suppose we want to add a new shipping method, like Overnight Shipping, without modifying existing classes:
// New class for Overnight Shipping public class OvernightShipping : ShippingMethod { public override double CalculateShippingCost(double orderTotal) { // Overnight shipping cost calculation logic return 50; // Flat rate for overnight shipping } }
In this example
- The ShippingMethod abstract class and its concrete implementations (StandardShipping and ExpressShipping) are closed for modification because we don't need to change them to introduce OvernightShipping.
- The system is open for extension because we can introduce new types of ShippingMethod(like OvernightShipping) without altering existing code.
Benefits of Open Closed Principle
- Maintainability: Existing code remains unchanged, reducing the risk of introducing bugs in previously tested code.
- Extensibility: New functionality can be added easily by creating new classes or modules rather than modifying existing ones.
- Testability: With well-defined interfaces or base classes, unit testing becomes straightforward, focusing on specific behaviors.
The Open/Closed Principle encourages designing systems that can be extended with new functionality without requiring changes to existing code. This promotes code reuse, maintainability, and reduces the risk of introducing bugs when extending the system. By adhering to this principle, software becomes more adaptable to changing requirements and easier to maintain over time.