Strategy Pattern
Last updated
Last updated
The strategy pattern intends to encapsulate a family of algorithms in classes that can be injected easily in the client code, so you can determine how the code behaves and which algorithm it uses to do a certain task during runtime.
Sometimes you may be tempted to write the algorithm you use inside the client code directly, the problem starts to appear when the algorithm grows big, you'll be violating some principles as the single responsibility principle since the client code became responsible to maintain the complex algorithm code, beside the other things as preparing the input, or using the output of the algorithm. You'll also face a hard time if you want to change the algorithm code when it's coupled between other lines of code, or if you want to provide more than one algorithm to be run at different scenarios the headache of doing this will become a huge deal.
When you have multiple algorithms, and you want to be able to change which one you use during run-time.
When you need to separate the responsibility of the algorithm code from the client code.
When the algorithms are complex and large so you'll achieve a really good separation of concerns, and of course you'll be adhering to the Open/Closed Principle, since adding a new algorithm only requires a new file.
Strategy: defines the interface that's common to all of the algorithms, the client uses the Strategy
type to inject a ConcreteStrategy
.
ConcreteStrategy: the concrete implementation for the algorithms.
Context: the context is the object that stores an instance of the Strategy
and uses it to do a certain action. Remember that it's not the responsibility of the context to choose which strategy to use, instead it's the client code's responsibility.
🟢 It removes the need for conditional statements to choose which strategy to use (although this may be delegated to the client or some other class if you want it to change in runtime based on some condition).
🟢 Inheriting from the base class can factor out all of the common functionality between the concrete strategies.
🟢 Since it implements multiple algorithms, the client may choose different algorithms based on the input to save time, or space.
🔴 Many strategy objects may be instantiated which in some cases may affect the memory, but this can be handled using a registry for the strategies if they are stateless, or even using the Flyweight Pattern to factor out common state.
🔴 If the base strategy needs a lot of data for some of the strategies, you may find yourself filling some parameters in the client and the strategy you end up using never uses them.
Flyweight Pattern You can build the strategy objects as flyweight to save memory utilizing common states.
Template Method Pattern You can factor out the repeated logic in the strategies in the AbstractStrategy
to act as a template method pattern.
You can also use strategies as functions, strategies are not required to be objects, and you may have seen this before as the comparator
functions for sorting algorithms on most programming languages.
Example
Description
An Error Notifier
that supports multiple platforms.