Design patterns: Strategy, Observer and Template method
Strategy: put interchangeable algorithms behind one interface and pick one at run time. With lambdas, a strategy is often just a Function or a small interface. Comparator is a strategy.
Observer (publish and subscribe): when something happens, notify everyone who registered interest, without the publisher knowing who they are. Spring's ApplicationEventPublisher with @EventListener, and Kafka at a larger scale, follow this pattern.
Template method: a base class fixes the steps of an algorithm and lets subclasses fill in some of them. Spring's JdbcTemplate follows the idea: it handles connections and errors while you supply the query and the row mapping.
Others you'll meet: Adapter (wrap an incompatible API), Decorator (add behaviour by wrapping, like BufferedReader around a Reader) and Proxy (how Spring implements @Transactional).
Example
// Strategy with lambdas
public enum Discount {
NONE(p -> p), FESTIVE(p -> p * 0.8), STUDENT(p -> p * 0.5);
private final DoubleUnaryOperator rule;
Discount(DoubleUnaryOperator rule) { this.rule = rule; }
public double apply(double price) { return rule.applyAsDouble(price); }
}
double price = Discount.FESTIVE.apply(1999); // 1599.2
// Observer with Spring events
public record OrderPaid(long orderId, String email) {}
@Service
class PaymentService {
private final ApplicationEventPublisher events;
PaymentService(ApplicationEventPublisher events) { this.events = events; }
void markPaid(long orderId, String email) {
// ... update the order
events.publishEvent(new OrderPaid(orderId, email)); // doesn't know who listens
}
}
@Component
class ReceiptMailer {
@TransactionalEventListener // runs after the transaction commits
void on(OrderPaid e) { /* send the receipt email */ }
}
@Component
class EnrollmentGranter {
@EventListener
void on(OrderPaid e) { /* unlock the course */ }
}Common mistake
Sending emails from a plain event listener inside the transaction. If the transaction rolls back, the email has already gone; listen after commit.
Under the hood
A plain @EventListener runs synchronously in the publisher's thread and transaction. Use @TransactionalEventListener (after commit by default) so emails aren't sent for orders that later roll back, and add @Async if listeners are slow. Patterns are vocabulary, not goals: saying "this is a strategy" in a review or interview communicates a design in one sentence.
Check yourself
Which pattern does java.util.Comparator represent?
How this connects
Know these first
Where this leads
You've reached the end of this thread. Try a learning path for what's next.
Was this lesson helpful?
Finished reading? Mark it complete to track your progress.