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.