Strategy pattern is a behavioral design pattern that allows the behavior of an object to be selected at runtime. It is one of the Gang of Four (GoF) design patterns, which are widely used in object-oriented programming.
The Strategy pattern is based on the idea of encapsulating a family of algorithms into separate classes that implement a common interface. The pattern consists of three main components: the Context, the Strategy, and the Concrete Strategy.
The Context is the class that contains the object whose behavior needs to be changed dynamically. The Strategy is the interface or abstract class that defines the common methods for all the algorithms that can be used by the Context object. The Concrete Strategy is the class that implements the Strategy interface and provides the actual implementation of the algorithm.
To use the Strategy pattern, you first create a Context object. Then, you create one or more Concrete Strategy objects that implement the Strategy interface. Finally, you set the Strategy object for the Context object by calling its setStrategy() method. At runtime, the Context object uses the selected Concrete Strategy object to perform its operations.
The Strategy pattern provides several advantages, including:
- Flexibility: The Strategy pattern allows the behavior of an object to be changed dynamically at runtime by selecting different algorithms.
- Modularity: The pattern encapsulates the algorithms in separate classes, making it easy to add or remove algorithms without affecting other parts of the code.
- Testability: The pattern makes it easy to test the different algorithms separately, without affecting the overall behavior of the code.
- Open-Closed Principle: The Strategy pattern follows the Open-Closed Principle, which states that a class should be open for extension but closed for modification.
- However, the Strategy pattern can also have some drawbacks, including increased complexity due to the use of multiple classes, and potential performance issues if the selection of algorithms is done frequently at runtime.
Overall, the Strategy pattern is a useful design pattern that allows the behavior of an object to be selected dynamically at runtime, providing flexibility, modularity, and testability.
As always we will learn this pattern by defining a problem and using a strategy pattern to solve it. Suppose we are building a game “Street Fighter”. For simplicity assume that a character may have four moves that is kick, punch, roll, and jump. Every character has kick and punch moves, but roll and jump are optional. How would you model your classes? Suppose initially you use inheritance and abstract out the common features in a Fighter class and let other characters subclass Fighter class.
Fighter class will have a default implementation of normal actions. Any character with specialized move can override that action in its subclass. Class diagram would be as follows:
What are the problems with above design? What if a character doesn’t perform jump move? It still inherits the jump behavior from superclass. Although you can override jump to do nothing in that case but you may have to do so for many existing classes and take care of that for future classes too. This would also make maintenance difficult. So we can’t use inheritance here.
What about an Interface? Take a look at the following design:
It’s much cleaner. We took out some actions (which some characters might not perform) out of Fighterclass and made interfaces for them. That way only characters that are supposed to jump will implement the JumpBehavior.
What are the problems with the above design?
The main problem with the above design is code reuse. Since there is no default implementation of jump and roll behavior we may have code duplicity. You may have to rewrite the same jump behavior over and over in many subclasses.
How can we avoid this?
What if we made JumpBehavior and RollBehavior classes instead of interface? Well then we would have to use multiple inheritance that is not supported in many languages due to many problems associated with it.
Here strategy pattern comes to our rescue. We will learn what the strategy pattern is and then apply it to solve our problem.
Wikipedia defines strategy pattern as:
“In computer programming, the strategy pattern (also known as the policy pattern) is a software design pattern that enables an algorithm’s behavior to be selected at runtime. The strategy pattern
- defines a family of algorithms,
- encapsulates each algorithm, and
- makes the algorithms interchangeable within that family.”
Here we rely on composition instead of inheritance for reuse. Context is composed of a Strategy. Instead of implementing a behavior, the Context delegates it to Strategy. The context would be the class that would require changing behaviors. We can change behavior dynamically. Strategy is implemented as an interface so that we can change behavior without affecting our context.
We will have a clearer understanding of strategy patterns when we will use them to solve our problem.
- A family of algorithms can be defined as a class hierarchy and can be used interchangeably to alter application behavior without changing its architecture.
- By encapsulating the algorithm separately, new algorithms complying with the same interface can be easily introduced.
- The application can switch strategies at run-time.
- Strategy enables the clients to choose the required algorithm, without using a “switch” statement or a series of “if-else” statements.
- Data structures used for implementing the algorithm are completely encapsulated in Strategy classes. Therefore, the implementation of an algorithm can be changed without affecting the Context class.
- The application must be aware of all the strategies to select the right one for the right situation.
- Context and the Strategy classes normally communicate through the interface specified by the abstract Strategy base class. Strategy base class must expose interface for all the required behaviours, which some concrete Strategy classes might not implement.
- In most cases, the application configures the Context with the required Strategy object. Therefore, the application needs to create and maintain two objects in place of one.
Further Read – Strategy Method in Python
If you like GeeksforGeeks and would like to contribute, you can also write an article and mail your article to email@example.com. See your article appearing on the GeeksforGeeks main page and help other Geeks. Please write comments if you find anything incorrect, or if you want to share more information about the topic discussed above.
Feeling lost in the vast world of System Design? It's time for a transformation! Enroll in our Mastering System Design
From Low-Level to High-Level Solutions - Live Course and embark on an exhilarating journey to efficiently master system design concepts and techniques.
What We Offer:
- Comprehensive Course Coverage
- Expert Guidance for Efficient Learning
- Hands-on Experience with Real-world System Design Project
- Proven Track Record with 100,000+ Successful Enthusiasts