Design Patterns: Strategy Pattern in Dart
In software engineering, a design pattern is a general repeatable solution to a commonly occurring problem in software design. A design pattern isn’t a finished design that can be transformed directly into code. It is a description or template for how to solve a problem that can be used in many different situations.
Design patterns can speed up the development process by providing tested, proven development paradigms. Effective software design requires considering issues that may not become visible until later in the implementation. Reusing design patterns helps to prevent subtle issues that can cause major problems and improves code readability for coders and architects familiar with the patterns.
In this blog post, we’ll be focusing on the Strategy Pattern from the 23 original patterns in the Gang of Four Catalog. We will learn this pattern by defining a problem and using the strategy pattern to solve it.
Suppose we are building a game “Tekken 3 ”. For simplicity assume that a character may have four moves i.e kick, punch, roll and jump. Every character has the 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 we have a default implementation of normal actions. Any character with a specialized move can override that action in its subclass. A class diagram would be as follows:
What are the problems with the above design?
What if a character doesn’t perform jump move? It still inherits the jump behavior from the 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 Fighter class 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 like dart 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.
Definition:
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.”
Class Diagram:
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 Pattern when we will use it to solve our problem.
Implementation
The first step is to identify the behaviors that may vary across different classes in the future and separate them from the rest. For our example let them be kick and jump behaviors. To separate these behaviors we will pull both methods out of Fighter class and create a new set of classes to represent each behavior.
The Fighter class will now delegate its kick and jump behavior instead of using kick and jump methods defined in the Fighter class or its subclass.
After reworking the final class diagram would be:
Comparing our design to the definition of strategy pattern encapsulated kick and jump behaviors are two families of algorithms. And these algorithms are interchangeable as evident in implementation.
Below is the Dart implementation of the same.
Output
Hi, I am Paul
Punch
This is a Tornado Kick
This is a Short Jump
This is a Long Jump
Advantages:
- 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.
Disadvantages:
- 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 behaviors, 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.
References:
- Head First Design Patterns
- http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Fall_2007/wiki1b_8_sa
- https://en.wikipedia.org/wiki/Strategy_pattern
- https://www.geeksforgeeks.org
If you would like to learn more, check out lots of tutorials on my
YouTube Channel “MTECHVIRAL”: https://www.youtube.com/c/MTechViral
Open Source Repos: https://github.com/iampawan/
Facebook Group: https://www.facebook.com/groups/425920117856409/
More Links & About me: https://pawan.live
I hope you have enjoyed my another attempt to write a blog post, Thank you for reading so far.
Happy developing! If you enjoyed the article make sure to show me some love and hit that clap button!