OPEN - CLOSED PRINCIPLE
The integral parts of a code should be open for extension and closed for modification.
The idea is to avoid relying on conditional checks using if-else, ternary operators, and switch.
When a new requirement arrives, you add the behavior by creating something new, without modifying the old code.
TO BE FAIR
The idea of not using conditional operators is a result of correctly applying OCP, not the focus itself.
This is because in order to not depend on these operators, excellence in applying polymorphism and abstraction is necessary.
With this, it becomes possible to couple new implementations without rewriting the already existing code.
BAD EXAMPLE
Every new payment method will cause an edit here. It makes new implementations difficult and puts the old ones at risk.
Code Example:
// BAD: Tight coupling. The class needs to be modified for each new rule.
class PaymentProcessor {
public process(amount: number, method: 'CREDIT_CARD' | 'PIX' | 'PAYPAL'): void {
if (method === 'CREDIT_CARD') {
console.log(`Processing $${amount} via Credit Card...`);
// Complex logic for acquirer integration...
}
else if (method === 'PIX') {
console.log(`Processing $${amount} via Pix key...`);
// Complex logic for QRCode generation...
}
else if (method === 'PAYPAL') {
console.log(`Processing $${amount} via PayPal...`);
// Complex redirection logic...
}
else {
throw new Error('Payment method not supported.');
}
}
}
GOOD EXAMPLE
Just fulfill the “IPaymentMethod” contract and the method is already valid.
We can then add a “DebitCardPayment”, without affecting the other methods.
Code Example:
// 1. The Abstraction (The Contract)
interface IPaymentMethod {
processPayment(amount: number): void;
}
// 2. The Extensions (New isolated behaviors)
class CreditCardPayment implements IPaymentMethod {
public processPayment(amount: number): void {
console.log(`Processing $${amount} via Credit Card...`);
}
}
class PixPayment implements IPaymentMethod {
public processPayment(amount: number): void {
console.log(`Processing $${amount} via Pix key...`);
}
}
// 3. The Closed Application (The Consumer)
class PaymentProcessor {
public process(amount: number, paymentMethod: IPaymentMethod): void {
paymentMethod.processPayment(amount);
}
}
// Practical use:
const processor = new PaymentProcessor();
processor.process(150.0, new PixPayment());
IS IT REALLY THAT IMPORTANT?
Without hesitation, yes, very much!
Rework is expensive: it is wasted labor, planning, and time.
And besides that, constantly altering already “finished” code opens up more loopholes to break a business rule or feature that was already working.
My Links
Github: victor-lis-bronzo
Linkedin: victor-lis-bronzo
Portfolio: portfolio.victorlisbronzo.me
Coolest Portfolio: victorlisbronzo.me
Leave your reaction ❤️
Have you ever needed to refactor old code because of poorly applied OCP?
Top comments (0)