Open/Closed Principle (OCP)
Concept
The Open/Closed Principle (OCP) states that software entities (classes, modules, functions) should be open for extension, but closed for modification.
This means you should be able to add new functionality or behaviors to a system without altering the existing source code. Modifying existing, tested, and working code introduces the risk of breaking it.
The Problem (Violation)
Consider a payment processor that needs to handle different payment methods:
class PaymentProcessor {
process(paymentType: string, amount: number) {
if (paymentType === 'CreditCard') {
console.log(`Processing ${amount} via Credit Card API`);
} else if (paymentType === 'PayPal') {
console.log(`Processing ${amount} via PayPal API`);
}
// If we add Bitcoin, we have to modify this file!
else if (paymentType === 'Bitcoin') {
console.log(`Processing ${amount} via Bitcoin Network`);
}
}
}
Every time a new payment method is introduced, we must crack open the PaymentProcessor class and add another else if block. This violates OCP.
The Solution
Use polymorphism (Interfaces and Inheritance) to extend behavior without touching existing code.
// 1. Define an abstraction
interface PaymentMethod {
processPayment(amount: number): void;
}
// 2. Create concrete implementations
class CreditCardPayment implements PaymentMethod {
processPayment(amount: number) {
console.log(`Processing ${amount} via Credit Card API`);
}
}
class PayPalPayment implements PaymentMethod {
processPayment(amount: number) {
console.log(`Processing ${amount} via PayPal API`);
}
}
// 3. The main class relies on the abstraction
class PaymentProcessor {
process(method: PaymentMethod, amount: number) {
// The processor doesn't care HOW it's processed.
method.processPayment(amount);
}
}
Now, if we want to add Bitcoin, we simply create a new BitcoinPayment class that implements PaymentMethod. We extended the system, but we completely avoided modifying the PaymentProcessor class.
Real-World Use Case
- Plugin Systems: Your web browser (Chrome) doesn’t need to be recompiled and updated every time someone creates an ad-blocker. Chrome is closed for modification, but exposes a strict API that makes it open for extension via plugins.
- Middleware: Express.js allows developers to inject middleware into the request lifecycle without modifying the core Express library.
Interview Questions
Q: Does OCP mean I can never change existing code?
A: No. You absolutely modify existing code when fixing bugs or refactoring internal logic. OCP specifically applies to adding new business requirements or features. New features should ideally be added by writing new code that plugs into existing abstractions, rather than scattering if/else statements throughout your core domains.