Behavioral patterns deal with communication and responsibility distribution between objects.
Strategy defines a family of interchangeable algorithms, encapsulates each one, and lets them be swapped independently of the code that uses them — a direct, practical application of the Open/Closed Principle from the SOLID chapter.
interface DiscountStrategy {
function apply(price): number
}
class NoDiscount implements DiscountStrategy {
function apply(price) { return price }
}
class PercentageDiscount implements DiscountStrategy {
function __construct(private percent) {}
function apply(price) { return price * (1 - this.percent / 100) }
}
class FlatDiscount implements DiscountStrategy {
function __construct(private amount) {}
function apply(price) { return max(0, price - this.amount) }
}
class ShoppingCart {
function __construct(private DiscountStrategy strategy) {}
function checkout(price) {
return this.strategy.apply(price)
}
}
cart = new ShoppingCart(new PercentageDiscount(20))
print(cart.checkout(100)) // 80
Adding a new discount type means writing a new class, never touching ShoppingCart itself. This is essentially the Open/Closed Principle applied specifically to swappable behavior rather than swappable object creation (as Factory handles).
Observer defines a one-to-many relationship where, when one object (the subject) changes state, all its dependents (the observers) are automatically notified — the foundation of most event-driven systems, GUI frameworks, and reactive programming.
class NewsPublisher {
private subscribers = []
function subscribe(observer) { this.subscribers.push(observer) }
function publish(article) {
for subscriber in this.subscribers:
subscriber.notify(article) // every subscriber is informed automatically
}
}
class EmailSubscriber {
function notify(article) { print("Emailing article: " + article) }
}
class SmsSubscriber {
function notify(article) { print("Texting article: " + article) }
}
publisher = new NewsPublisher()
publisher.subscribe(new EmailSubscriber())
publisher.subscribe(new SmsSubscriber())
publisher.publish("Breaking News!") // both subscribers are notified
The NewsPublisher doesn't need to know anything specific about EmailSubscriber or SmsSubscriber beyond the shared notify() contract — new subscriber types can be added freely without modifying the publisher at all. This pattern underlies event listeners in web browsers, GUI button clicks, and pub/sub messaging systems used across countless real-world applications.