Card 03/ 09
All 9 cards
ExampleDifficulty: Intermediate1 min
One Loop Over Three Payment Methods
A refund run over yesterday's failed orders. Each order was paid in a different way, and each way of paying knows how to reverse itself.
interface PaymentMethod { Receipt refund(BigDecimal amount); }
class Card implements PaymentMethod {
public Receipt refund(BigDecimal amount) { return gateway.reverse(token, amount); }
}
class BankTransfer implements PaymentMethod {
public Receipt refund(BigDecimal amount) { return bank.credit(iban, amount); }
}
class StoreCredit implements PaymentMethod {
public Receipt refund(BigDecimal amount) { return wallet.topUp(userId, amount); }
}for (Order order : failedYesterday) {
Receipt receipt = order.paymentMethod().refund(order.total());
audit.record(receipt);
}Three completely different things happen on line 2 — a call to a card gateway, a bank credit, a wallet top-up — and the loop names none of them. Adding a fourth way to pay adds a class and changes nothing here.
Put this beside the shapes and the shared structure comes out, which is worth stating rather than leaving to be noticed: in both, one variable's declared type names a capability, the objects behind it are several different classes, and neither loop contains a single if. The domains have nothing in common; the mechanism is identical.