Give a real example of polymorphism in a production system, and explain why the design pays off as requirements change.
Payments are the standard example because new methods appear constantly and they behave differently. The service is written against the Payment interface, so it contains no branch on the payment type. Each implementation knows how to describe itself, and adding a new one, such as a bank transfer or a voucher, means adding a class and nothing else.
public class Main {
public static void main(String[] args) {
PaymentService service = new PaymentService();
service.pay(new CardPayment("Ada", 25.0));
service.pay(new WalletPayment("Bob", 10.0));
}
}
interface Payment {
String describe();
}
class CardPayment implements Payment {
private final String holder;
private final double amount;
CardPayment(String holder, double amount) { this.holder = holder; this.amount = amount; }
public String describe() { return "card " + holder + " " + amount; }
}
class WalletPayment implements Payment {
private final String owner;
private final double amount;
WalletPayment(String owner, double amount) { this.owner = owner; this.amount = amount; }
public String describe() { return "wallet " + owner + " " + amount; }
}
class PaymentService {
void pay(Payment payment) { System.out.println("paid: " + payment.describe()); }
}The output shows the service handling both kinds without knowing about either. Both objects satisfy the same contract, the service calls describe through the interface reference, and the runtime dispatches to the right implementation each time.
Why this pays off as requirements change is the part to spell out. When a third method is needed, the service and its tests are untouched. When the card provider changes its format, only the card class changes. The contract stays stable while the behaviour behind it varies, which is the open for extension, closed for modification property in practice.
The same shape appears in logging sinks, in storage backends, in retry strategies and in plugin registries. The common structure is a small interface owned by the consumer, one or more implementations owned by whoever needs them, and a wiring point where the choice is made. That last part matters too, because it is where the concrete type is named, and it is the only place that has to change.