980 likes | 1.12k Views
Chapter 23 Strategy. Summary prepared by Kirk Scott. Design Patterns in Java Chapter 23 Strategy. Summary prepared by Kirk Scott. The Introduction Before the Introduction. In general, a single strategy might be thought of as an algorithm or an operation
E N D
Chapter 23Strategy Summary prepared by Kirk Scott
Design Patterns in JavaChapter 23Strategy Summary prepared by Kirk Scott
The Introduction Before the Introduction • In general, a single strategy might be thought of as an algorithm or an operation • In the context of the Strategy design pattern, the idea is that there are multiple approaches to doing something, depending on certain conditions or context • The Strategy design pattern, then, depends on picking the approach or picking the strategy
When there is more than one way to go about doing something, complexity can result • There are the implementations of the different strategies • There is also the code for choosing which strategy to use
The purpose of the Strategy design pattern is to separate the implementations of different strategies from each other • It also separates the code for picking the strategy from the strategy implementations
The pattern defines a single interface for all strategies • The separate strategies are implemented with a method of the same name in each of the classes implementing the interface
Which strategy is used will depend on what kind of object the method implementing the strategy is called on • The intent of the pattern is realized through an interface and depends on polymorphism and dynamic binding
Book Definition of Pattern • Book definition: • The intent of Strategy is to encapsulate alternative approaches, or strategies, in separate classes that each implement a common operation.
Modeling Strategies • Like with the previous chapters, and others, the book illustrates the Strategy design pattern in the following way: • It develops an example with multiple strategies that doesn’t use the Strategy design pattern • It then refactors the example using the Strategy design pattern
Example Scenario • When a potential customer calls in, interested in buying fireworks, there is software which will make a recommendation or suggestion • There are several different ways a recommendation can be made
Ways of recommending a purchase: • Recommend a particular firework that is being promoted • Use a piece of software, Rel8 • Use another piece of software, LikeMyStuff • Use a default recommendation option
Promoted Firework • There is nothing special about this option • If the company is promoting a firework, recommend it
Rel8 • Rel8 relies on a customer’s already being registered • During registration the customer specifies preferences in entertainment and fireworks • Rel8 makes a suggestion based on the similarity of the customer to other customers (presumably suggesting something that similar customers have tended to buy) • If the customer isn’t registered, Rel8 can’t be used
LikeMyStuff • LikeMyStuff doesn’t rely on pre-registration, but it does rely on customer information • The idea is that it will make a recommendation based on a profile of recent purchases by the customer • If not enough data can be obtained to form the profile, then LikeMyStuff can’t be used
The Default Option • This is the default: • If none of the previous options applies, then a firework is suggested at random
UML for the Scenario • The UML diagram on the following overhead shows the classes involved in the design as described so far • Appendix D on UML clarifies the notation: • “Use a dashed arrow between classes to show a dependency that does not use an object reference. For example, the Customer class relies on a static method from the LikeMyStuff recommendation engine.”
The getRecommended() Method • Viewing the scenario from the top down, what you have is this: • The Customer class has a getRecommended() method in it • This method consists of if/else code which chooses one of the strategies, whether to do a promotion, or to use Rel8, LikeMyStuff, or the default
Doing a Promotion • If there is a promotion underway, the first part of the logic of getRecommended() deals with that case • The logic for doing a promotion consists of looking up the contents of a file named strategy.dat in a directory named config • If there is such a file, its contents should look something like this: promote=JSquirrel
The basic idea is that if the data file is not empty, the firework it contains is returned • If its contents come up null you go on to the next option • Also, if the file read doesn’t work, you don’t do anything in the catch block, you just continue on to the other options
Using Rel8 • The Rel8 class has a method advise() • getRecommended() wraps a call to advise() if the Rel8 strategy is selected • The call looks like this: • if(isRegistered()) • return (Firework) Rel8.advise(this); • “this” is the customer, and Rel8 relies entirely on the information contained in the registered customer object
Using LikeMyStuff • The LikeMyStuff class has a suggest() method • getRecommended() wraps a call to suggest() if the LikeMyStuff strategy is selected • The call looks like this: • if(spendingSince(cal.getTime()) > 1000) • return (Firework) LikeMyStuff.suggest(this);
spendingSince() is called on the implicit parameter, customer • cal in the parameter refers to an instance of Calendar • getTime() specifies a recent period of time • “this” is the customer, which is sent as a parameter to suggest()
suggest() relies on a database of recent purchases by that customer • The idea is that if the customer has recently spent $1,000, those purchases provide the basis for a recommendation
Doing the Default • The Firework class has a getRandom() method, so if all else fails, getRecommended() wraps a call to that method
The Code for getRecommended() in the Customer Class • The code for getRecommended() is shown on the following overheads • It is a collection of if statements. • It is unfortunate that it is not organized as a sequence of if/else if’s.
The Code for getRecommended() • public Firework getRecommended() • { • // if promoting a particular firework, return it • try • { • Properties p = new Properties(); • p.load(ClassLoader.getSystemResourceAsStream(“config/strategy.dat”)); • String promotedName = p.getProperty(“promote”); • if(promotedName != null) • { • Firework f = Firework.lookup(promotedName); • if(f != null) • return f; • }
catch(Exception ignored) • { • // If resource is missing or it failed to load, • // fall through to the next approach. • } • // if registered, compare to other customers • if(isRegistered()) • { • return (Firework) Rel8.advise(this); • }
// check spending over the last year • Calendar cal = Calendar.getInstance(); • cal.add(Calendar.YEAR, -1); • if(spendingSince(cal.getTime()) > 1000) • return (Firework) LikeMyStuff.suggest(this); • // oh well! • return Firework.getRandom(); • }
What’s Wrong with the Initial Design • The book identifies two basic problems with the getRecommended() method as given: • It’s too long • It combines both selecting a strategy and executing it
This is actually one of the high points of the book • It explains that you know that the method is too long because you need to put comments in it • “Short methods are easy to understand, seldom need explanation…”
Comments Are Bad… • Finally, what every student always knew: Comments are bad… • More accurately, you might facetiously say that code which requires comments is bad. • The book doesn’t say that putting a comment at the beginning for the whole method is bad. • A useful observation might be that a method should be short and sweet enough that it doesn’t need internal commenting.
Refactoring to the Strategy Pattern • Applying the Strategy design pattern involves three things: • 1. Creating an interface that defines the strategic operation • 2. Writing classes that implement the interface and embody each of the different strategies • 3. Refactoring the code to select and use an instance of the right strategy class
The Interface • 1. The interface for this example will be named Advisor • The interface requires the implementation of a recommend() method • The recommend() method will take a customer as a parameter • It will return a firework • A UML diagram of the interface is given on the next overhead
The Implementing Classes • 2. The next step is to write the classes that implement the interface and embody each of the different strategies • These classes will have to implement the recommend() method
The book does the refactoring in part with challenges • As usual, it’s easiest to just look at the solutions • The UML diagram on the following overhead shows: • A new Customer class making use of an Advisor interface • 4 classes which implement the interface and embody the 4 strategies
The Implementing Classes • The PromotionAdvisor and RandomAdvisor class names should be self-explanatory • GroupAdvisor refers to the use of Rel8 • ItemAdvisor refers to the use of LikeMyStuff • The implementations of the recommend() method for these classes will wrap a call to the static methods of Rel8 and LikeMyStuff • An expanded UML diagram for these two classes is given on the next overhead
Making Instances of the Implementing Classes • An interface can’t define static methods • An interface defines what the book calls “object methods”—methods that are called on objects • That means that client code will have to make instances of GroupAdvisor and ItemAdvisor • The recommend() method will be called on these objects
Only one instance each of GroupAdvisor and ItemAdvisor are needed • In the refactored design, these instances will be static objects in the Customer class • So the advisor objects will be “singleton like” • There won’t be an instance of each kind of advisor for each customer
Even though the recommend() method isn’t a static method, it more or less acts like one • If there is only one advisor object, then there is the one recommend() method that can be called on that object • The recommend() method does something for customers • But it does so by taking the customer as an explicit parameter rather than being called on the customer
Code for the recommend() Method in the GroupAdvisor Class • This is the recommend() method in the GroupAdvisor class: • public Firework recommend(Customer c) • { • return (Firework) Rel8.advise(c); • } • It wraps a call to the advise() method of Rel8 • In essence, the call is adapted to the recommend() interface of Advisor
Code for the recommend() Method in the ItemAdvisor Class • The code for the recommend() method in the ItemAdvisor class is analogous. • The book doesn’t give it and it doesn’t even bother to give it as a challenge. • It should be straightforward to write that method.
Challenge 23.2 • “In addition to Strategy, what pattern appears in the GroupAdvisor and ItemAdvisor classes?” • [The answer to this was given away in the last remark about the recommend() code in GroupAdvisor.]
Solution 23.2 • “The GroupAdvisor and ItemAdvisor classes are instances of Adapter, providing the interface a client expects, using the services of a class with a different interface.”
Code for the recommend() Method in the PromotionAdvisor Class • A PromotionAdvisor class is also needed, with a recommend() method • On the one hand, promotion should be a simple case • On the other hand, the book puts a lot of detail into the implementation