What's this all about?
One of my unofficial goals this year is to gain a better understanding of software design patterns, how to use them in my projects, and when it's appropriate to do so. Since I believe that we learn more when we share what we learn, I hope to periodically post a short article on a design pattern that I am either learning or reading about, or that I feel I have experience with. I will seek to make these articles brief and to the point so that they could be used as a quick reference for anyone wanting to learn about a given pattern. I encourage you to make comments and provide insight where I may not have.
To be fair to you the reader, I am not yet a wizard level software engineer with decades of insight and war stories from coding in the trenches. I am, however, passionate about my craft and eager to take a journey with you on the path to enlightenment. I think this is all the fluff you the reader can handle for now, so I will move to the topic at hand.
A common problem
Imagine that you are developing a new and completely original game, titled "Knights vs Dragons". In this medieval game you want the player to be able to unlock different types of knights as he or she progresses through the various levels and earns experience. A new player, having no experience, will start off the game with access to only one character, the Basic Knight.
Level 1
Basic Knight
The Basic Knight has one weapon, a wooden sword meant for vanquishing straw stuffed foes while our player learns the ropes in the tutorial. Figuring that you know a lot about Knights you decide to give the Basic Knight the following behaviors:
Great, this knight does everything you want him to do and doesn't complain. He can walk, talk, fight, and display. The display() method is for rendering the Knight on the screen. It is really only included as a visual placeholder for methods that won't be a part of our Strategy pattern, although you certainly could use a DisplayStrategy.
Level 2
Dagger Wielding Knight
The Dagger Wielding Knight has a dagger for his weapon, which is certainly an improvement over the the Basic Knight. This, however, presents a problem: the Dagger Wielding Knight will need to know how to fight differently from the Basic Knight but will still walk and talk the same. Remembering from a college course you took on Object Oriented Design, you should isolate what changes from what stays the same. So you decide to simply abstract the common knight behavior into an AbstractKnight class. That way each class that extends from the Abstract class can choose what behavior to override and what to reuse.
Great! Both Knights appear to have their own unique fighting style and there is no duplication of any code because both knights have reused what they have in common via the Abstract Knight.
Level 3, 4, 5, 6, 7
In levels 3-7 we introduce the following five knights to the roster:
Brimming from your recent success with the Basic Knight and the Dagger Wielding Knight you confidently create five more Knights that inherit from Abstract Knight when you realize that you are duplicating code everywhere . You already accounted for code duplication with the addition of inheritance so what happened?
It turns out that you still have not isolated the things that change from the things that stay the same. What changes other than the knight? Answer: the fighting technique.
The Strategy Pattern
Defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.-Design Patterns: Elements of Reusable Object Orientated Software
The Strategy Pattern is made up of three parts:
- A Strategy: An interface that allows access to an algorithm.
- A Concrete Strategy: Implements a particular algorithm to conform to the Strategy interface.
- A Context: Uses the algorithm through the Strategy interface.
The Strategy Pattern works by moving a group of related behaviors out of the context that calls on them and into their own group behind a common interface. The context can then refer to the interface and never be concerned with the implementation. Lets see how this fits in with the Knights vs Dragons game being built.
Summary
Using the Strategy Pattern has resulted in a design that concentrates the fighting behavior/algorithms into their own specific classes (Strategies). Another benefit is that it is simple to add new Strategies as the game requirements change. It is also now possible to reuse each Fight Strategy and hot swap them at run time. Maybe the Cowardly Knight regains his courage?
Pros
- Can be better than traditional sub-classing because you implement a simple interface as opposed to overriding methods from a inherited parent class for every desired behavior.
- Removes, from a context class, those implementation details that the context class either doesn't need to know, or in some cases should not know.
- Easy to extend, adding new concrete strategies.
- Adheres to best practice principles such as DRY and SRP.
Cons
- There are more objects created than in a traditional inheritance based solution.
- Some parameters on Strategy interface may be used in every case by every concrete strategy.
Sources
- Resources
- Gamma, Helm, Johnson, and Vlissides. Design Patterns: Elements of Reusable Object Orientated Software (Gang of Four). Reading, Mass.: Addison Wesley Longman, 1998. Print.
- Holub, Allen I. Holub on Patterns: Learning Design Patterns by Looking at Code. Print.
- Freeman, Eric, and Elisabeth Freeman. Head First Design Patterns. Sebastopol, CA: O'Reilly Media, 2005. Print.
- Geary, David. "Strategy for Success." 22 Apr. 2002. Web. <http://www.javaworld.com/article/2074195/swing-gui-programming/strategy-for-success.html>.
- Images
- Knights: Courtesy of hasslefreeclipart.com
No comments:
Post a Comment