Software entities should be open for extension, closed for modification.
Every new payment type requires modifying the processPayment switch in PaymentProcessor.
Define a stable PaymentHandler interface. Each payment type is a new class implementing it. PaymentRouter resolves by type — no switch statement.
// ─── EXAMPLE 1 ──────────────────────────────────────────────────────────────
// WHAT WE ARE IMPLEMENTING:
// A payment processing system allowing new payment gateways to be added
// without modifying existing checkout code.
//
// WHERE THE PRINCIPLE FITS IN:
// The system defines a PaymentGateway interface that is open for extension
// via StripePayment or PayPalPayment, but closed for modification in the
// client PaymentService.
// ────────────────────────────────────────────────────────────────────────────
// --- Stable interface (closed for modification) ---
interface PaymentHandler {
void process(double amount);
}
// --- Extensions (open for extension) ---
class CardPaymentHandler implements PaymentHandler {
public void process(double amount) {
System.out.println(" [Card] Processing " + amount + " via card gateway. Auth: " + (amount > 100 ? "3DS required" : "Normal"));
}
}
class UPIPaymentHandler implements PaymentHandler {
public void process(double amount) {
System.out.println(" [UPI] Processing " + amount + " via UPI. " + (amount > 5000 ? "OTP validation" : "Quick pay"));
}
}
class WalletPaymentHandler implements PaymentHandler {
public void process(double amount) {
System.out.println(" [Wallet] Processing " + amount + " via wallet. Balance check: " + (amount >= 500 ? "OK" : "Low balance fallback"));
}
}
// --- Resolver (no switch) ---
class PaymentRouter {
private final java.util.Map<String, PaymentHandler> handlers = new java.util.HashMap<>();
public PaymentRouter() {
// Register — one line per handler
handlers.put("CARD", new CardPaymentHandler());
handlers.put("UPI", new UPIPaymentHandler());
handlers.put("WALLET", new WalletPaymentHandler());
}
public PaymentHandler getHandler(String type) {
PaymentHandler handler = handlers.get(type.toUpperCase());
if (handler == null) throw new IllegalArgumentException("Unknown payment type: " + type);
return handler;
}
// To add NetBanking: no existing class modified.
// Add NetBankingPaymentHandler implements PaymentHandler
// Register: handlers.put("NETBANKING", new NetBankingPaymentHandler())
}
// --- Client ---
public class Main {
public static void main(String[] args) {
PaymentRouter router = new PaymentRouter();
for (String type : new String[]{"CARD", "UPI", "WALLET"}) {
System.out.println("Payment via " + type + ":");
router.getHandler(type).process(250.0);
}
}
}