Real World Example

Payment Methods at Checkout

Checkout pages on Flipkart or Amazon accept many payment methods. The checkout code talks only to the parent type Payment. Adding a new method (say, EMI) needs a new class, not changes to checkout.

Example

import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Payment> payments = List.of(
                new UpiPayment("asha@okbank"),
                new CardPayment("4111111111111111"),
                new CashOnDelivery());
        Checkout checkout = new Checkout();
        for (Payment p : payments) {
            checkout.pay(p, 1499);
        }
    }
}

class Checkout {
    void pay(Payment payment, double amount) {
        double fee = payment.fee(amount);
        System.out.printf("%s | amount %.2f + fee %.2f%n", payment.describe(), amount, fee);
    }
}

class Payment {
    String describe() { return "Payment"; }
    double fee(double amount) { return 0; }
}

class UpiPayment extends Payment {
    private final String vpa;
    UpiPayment(String vpa) { this.vpa = vpa; }
    @Override String describe() { return "UPI " + vpa; }
}

class CardPayment extends Payment {
    private final String cardNumber;
    CardPayment(String cardNumber) { this.cardNumber = cardNumber; }
    @Override String describe() { return "Card ****" + cardNumber.substring(12); }
    @Override double fee(double amount) { return amount * 0.02; }
}

class CashOnDelivery extends Payment {
    @Override String describe() { return "Cash on Delivery"; }
    @Override double fee(double amount) { return 40; }
}

Output

UPI asha@okbank | amount 1499.00 + fee 0.00
Card ****1111 | amount 1499.00 + fee 29.98
Cash on Delivery | amount 1499.00 + fee 40.00

Why This Design Works

  • Checkout never uses if (type == "UPI") chains.
  • Each payment type owns its own rules (fee, masking).
  • This is the Open/Closed principle: open for extension, closed for modification.