Part 1:
Going from a standard OO design using inheritance and abstract classes to one using the Strategy Pattern isn't all that huge of a leap. Instead of having to override behaviors in subclasses that are unable to perform them, you can use a variable to store the type of behavior to perform and then use an interface to perform the behavior.
Joe's problem with SimUDuck stemmed from the fact that he needed to extend it in a way that would add too much complexity to be easily maintained. He was trying to use inheritance to add a fly() method to every sub-Duck by adding it to the main Duck class. This had the unintended effect of granting flight capability to all sub-Ducks, including the ones that aren't supposed to fly: RubberDuck and DecoyDuck. If SimUDuck was a project that would never need maintaining or extending, it wouldn't be too bad to just override fly() in the few subclasses that aren't supposed to fly, but since this project is one that was still in progress, using inheritance and overrides would lead to major headaches for Joe. While this is a valid use of shadowing, it's confusing and doesn't lead to reuse of code.
The Strategy Pattern is a good solution for the problem Joe was faced with because it separates the behaviors from the objects that perform them. The big payoff is that after implementation, the Strategy Pattern provides a more organized and understandable way of reusing and unifying a method across a hierarchy of animates. Joe can add sub-Ducks whenever he wants and make changes to existing behaviors with very little effort compared to if he had just stuck with his standard OO design.
Part 2:
To implement the Strategy Pattern, follow these steps:
1.) Figure out which methods/behaviors are used multiple times across the hierarchy. ex: fly(), quack()
2.) Come up with a naming convention so you can keep all your behaviors straight and create classes for each of the distinct variations of the method, bringing the methods out of the superclass. ex: remove fly() from Duck and create fly(), nofly(), etc in the new classes
3.) Wrap the different versions of the behavior with an interface that can be called when behaviors need to be performed. ex: performFly()
4.) Reference an object of type interface (or rather, whatever you chose to name your interface) and use this object to set up which behavior to use
5.) Change the method in the base class to call the object from above and perform the appropriate method through the interface
Oliver is the 'Observer' cat on the copyright page and was surprisingly difficult to spot since it wasn't on a page that I read the first couple of times. Good trick to get us to re-read the section! :)
Friday, January 25, 2008
Subscribe to:
Post Comments (Atom)
1 comment:
Hi Josh,
Good job. It will be better if you put more words in the recipe, for example, explain how to choose the behavior into strategy pattern.
Chen
Post a Comment