Strategy Pattern
A behavioral design pattern that defines a family of interchangeable algorithms, encapsulates each one, and allows the algorithm to be selected at runtime.
Description
The Strategy pattern defines a family of algorithms or behaviors, encapsulates each one as a separate class or function, and makes them interchangeable through a common interface. The context object delegates algorithm execution to the current strategy object, which can be swapped at runtime. This eliminates conditional branching (long if-else or switch chains) by replacing them with polymorphism, adhering to the Open-Closed Principle: new strategies can be added without modifying existing code.
In TypeScript, strategies are naturally expressed as interfaces with a single method. A PricingStrategy interface with calculate(order: Order): Money can have implementations for StandardPricing, VolumePricing, SubscriberPricing, and PromotionalPricing. The OrderService receives the appropriate strategy based on the customer type or active promotions. In functional programming, strategies simplify to higher-order functions: sort(array, compareFn) is the Strategy pattern where compareFn is the strategy. React's render props and component injection (passing a component as a prop) are also strategy pattern applications.
The Strategy pattern is particularly valuable when an application has multiple ways of doing the same thing and the choice varies by configuration, user, or context: sorting algorithms, compression methods, authentication providers, notification channels, payment processors, or tax calculation rules. The pattern makes each variant independently testable and deployable. The key design decision is where the strategy selection happens—the client can choose directly, or a factory can select the strategy based on context, which is often cleaner for complex selection logic.
Prompt Snippet
Define a NotificationStrategy interface with a single method send(recipient: User, message: NotificationPayload): Promise<NotificationResult>, and implement EmailStrategy (using Resend SDK), SlackStrategy (using Slack Web API), and PushStrategy (using Firebase Cloud Messaging). Create a NotificationService that receives a Map<NotificationChannel, NotificationStrategy> via constructor injection and dispatches to the appropriate strategy based on the user's notification preferences stored in their profile. Add a CompositeStrategy that sends to multiple channels simultaneously using Promise.allSettled and returns a merged result. Each strategy should be independently unit-testable by mocking only its external SDK dependency.
Tags
Related Terms
Factory Pattern
A creational design pattern that encapsulates object creation logic, allowing the client to request objects without knowing the concrete class or complex construction details.
Dependency Injection
A design pattern where objects receive their dependencies from an external source rather than creating them internally, enabling loose coupling and testability.
Middleware Pattern
A pattern where request processing is composed as a chain of functions, each of which can inspect, transform, or short-circuit the request before passing it to the next handler.
State Machine Design
A modeling technique where system behavior is defined as a finite set of states with explicit transitions triggered by events, eliminating impossible states by design.