
Today, we’ll dive into the Open/Closed Principle (OCP) and
understand how it helps us extend application behavior without modifying
existing code.
🔓𝐎𝐏𝐄𝐍/𝐂𝐋𝐎𝐒𝐄𝐃
𝐏𝐑𝐈𝐍𝐂𝐈𝐏𝐋𝐄
(𝐎𝐂𝐏)
:
📌Definition:
“𝐒𝐨𝐟𝐭𝐰𝐚𝐫𝐞
𝐞𝐧𝐭𝐢𝐭𝐢𝐞𝐬
(𝐜𝐥𝐚𝐬𝐬𝐞𝐬,
𝐦𝐨𝐝𝐮𝐥𝐞𝐬,
𝐟𝐮𝐧𝐜𝐭𝐢𝐨𝐧𝐬)
𝐬𝐡𝐨𝐮𝐥𝐝
𝐛𝐞 𝐎𝐏𝐄𝐍
𝐟𝐨𝐫
𝐞𝐱𝐭𝐞𝐧𝐬𝐢𝐨𝐧
𝐛𝐮𝐭
𝐂𝐋𝐎𝐒𝐄𝐃
𝐟𝐨𝐫
𝐦𝐨𝐝𝐢𝐟𝐢𝐜𝐚𝐭𝐢𝐨𝐧.”
In simple words:
-> You should add new behavior.
-> WITHOUT changing existing, tested code.
❓Why OCP
Matters in Real Applications
In enterprise systems:
->Business rules change frequently
->New features are added regularly
->Existing code is already tested & deployed
❌ Modifying
old code introduces regression bugs.
✅ Extending
behavior reduces risk and downtime.
❌ WRONG WAY
(Violates OCP)
Real-world example: Payment Processing.
public class PaymentService {
public void processPayment(String type, double amount) {
if ("CREDIT_CARD".equals(type)) {
// credit card logic
} else if ("UPI".equals(type)) {
// upi logic
} else if ("DEBIT_CARD".equals(type)) {
// net banking logic
}
} }
❌ Problems:
->Every new payment method →
modify this class
->High risk of breaking existing flows
->Large if-else or switch blocks
👉 This
violates Open/Closed Principle.
✅ RIGHT WAY
(Follows OCP)
Step 1️⃣:
Define a Common Interface/Abstraction:
public interface PaymentProcessor {
void process(double amount);
}
Step 2️⃣:
Create Concrete Implementations:
public class CreditCardPayment implements PaymentProcessor {
public void process(double amount) {
// credit card logic
}
}
public class UpiPayment implements PaymentProcessor {
public void process(double amount) {
// upi logic
}
}
public class DebitCardPayment implements PaymentProcessor {
public void process(double amount) {
// debit card logic
}
}
Step 3️⃣:
Use Polymorphism (No Modification Needed):
public class PaymentService {
private final PaymentProcessor paymentProcessor;
public PaymentService(PaymentProcessor paymentProcessor) {
this.paymentProcessor = paymentProcessor;
}
public void processPayment(double amount) {
paymentProcessor.process(amount);
}
}
🔥Adding
New Feature (WITHOUT Changing Existing Code)
New Requirement: NetBankingPayment.
public class NetBankingPayment implements PaymentProcessor {
public void process(double amount) {
// net banking logic
}
}
✅ No changes
in PaymentService.
✅ Existing
code remains untouched.
🧠 How This
Works in Real Applications
In Spring Boot:
☑️
Interfaces → @Service
implementations
☑️
Dependency Injection selects implementation
☑️
Strategy Pattern applied naturally
Example:
@Service
public class CreditCardPayment implements PaymentProcessor {}
📌
Real-World Usage
✅Payment
gateways.
✅Notification
systems (Email, SMS, Push).
✅Pricing
strategies.
✅Discount
rules.
✅Authentication
providers.