When building applications, we often need to add new features or change behavior. A common mistake is modifying existing code every time we need something new.
This can easily introduce bugs and break parts of the system that were already working.
The Open-Closed Principle (OCP) helps solve this problem.
What is Open-Closed Principle?
The idea is simple:
Software entities should be open for extension, but closed for modification.
That means:
- You should be able to add new behavior
- Without changing existing code
Why This Matters
When we modify existing code:
- We risk breaking existing functionality
- Testing becomes harder
- The code becomes less stable over time
Instead, we should extend the code in a safe way.
Bad Example (Modifying Existing Code)
Let’s say we have a class that calculates discounts:
class DiscountService {
calculate(price, type) {
if (type === "regular") {
return price * 0.1;
} else if (type === "premium") {
return price * 0.2;
}
}
}
Problem here:
- Every time we add a new discount type, we must modify this class
- This can break existing logic
Good Example (Open for Extension)
Instead of modifying the class, we can extend behavior:
// Base class
class Discount {
calculate(price) {
return 0;
}
}
// Extended classes
class RegularDiscount extends Discount {
calculate(price) {
return price * 0.1;
}
}
class PremiumDiscount extends Discount {
calculate(price) {
return price * 0.2;
}
}
Now we use them like this:
function getDiscount(discount, price) {
return discount.calculate(price);
}
Why this is better:
- We don’t change existing code
- We add new behavior using new classes
- The system becomes more stable and flexible
Adding a new discount is easy:
class FestivalDiscount extends Discount {
calculate(price) {
return price * 0.3;
}
}
No need to modify old code.
Going One Step Further (Better Design)
In real-world applications, we often combine OCP with dependency injection.
class CheckoutService {
constructor(discount) {
this.discount = discount;
}
getFinalPrice(price) {
return price - this.discount.calculate(price);
}
}
Now we can pass any discount type:
const discount = new PremiumDiscount();
const checkout = new CheckoutService(discount);
console.log(checkout.getFinalPrice(100));
This makes the system flexible and easy to extend.
Real-Life Analogy
Think of a mobile phone:
- You don’t modify the phone to add new features
- You install apps to extend functionality
The phone is closed for modification but open for extension.
Key Idea to Remember
- Don’t modify existing working code
- Extend behavior using new classes
- Keep your system stable
Conclusion
At first, modifying existing code may seem easier. But as your project grows, it increases risk and complexity.
By following the Open-Closed Principle, your code becomes:
- Easier to extend
- Safer to maintain
- More scalable
Comments
Post a Comment