Download unit18cs304ch23x

Document related concepts

Business method patent wikipedia , lookup

Strategic management wikipedia , lookup

Service blueprint wikipedia , lookup

Transcript
Unit 18
Strategy
Summary prepared by Kirk Scott
1
Design Patterns in Java
Chapter 23
Strategy
Summary prepared by Kirk Scott
2
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
3
• When there is more than one way to go about
doing something, complexity can result
• Not only are there the different
implementations to consider
• There is also the code that is devoted to
making the choice of which strategy to use
4
• 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
5
• 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
6
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.
7
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
8
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:
• Either a particular firework is being promoted,
or two pieces of software, Rel8 or LikeMyStuff
can make a recommendation, or a default
option can be chosen
9
• 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
10
• 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
11
• This is the default:
• If none of the previous options applies, then a
firework is suggested at random
12
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.”
13
14
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
15
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
16
• 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
17
Using Rel8
• The Rel8 class has a method advise(), so
getRecommended() wraps a call to that method if
that 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
18
Using LikeMyStuff
• The LikeMyStuff class has a suggest() method,
so getRecommended() wraps a call to that
method if that strategy is selected
• The call looks like this:
• if(spendingSince(cal.getTime()) > 1000)
•
return (Firework) LikeMyStuff.suggest(this);
• “this” is the customer, and LikeMyStuff relies
on a database of recent purchases by that
customer, which is accessed by the call to
spendingSince() on the customer
19
• The Firework class has a getRandom()
method, so if all else fails, getRecommended()
wraps a call to that method
• 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.
20
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;
}
21
•
•
•
•
•
•
•
•
•
•
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);
}
22
•
•
•
•
•
// 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();
}
23
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
24
• 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…”
25
• 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.
26
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 represent each strategy
and implement the interface
• 3. Refactoring the code to select and use an
instance of the right strategy class
27
The Interface
• 1. The interface will be named Advisor
• The interface requires that an implementing
class have a method named recommend()
• 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
28
29
The Implementing Classes
• 2. The next step is to create the classes that
represent the different strategies and
implement the interface
• The book essentially presents this information
as part of the following challenge
30
• Challenge 23.1
• Fill in the class diagram in Figure 23.3, which
shows the recommendation logic refactored
into a collection of strategy classes.
• Comment mode on:
• What they want is mindlessly simple
• That will be clear when you see the answer
31
32
• Solution 23.1
• Figure B.24 shows one solution.
33
34
• 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
35
36
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
• Instances of GroupAdvisor and ItemAdvisor,
the classes that implement the interface, are
needed in order to call the methods defined in
the interface an implemented in them
37
• Only one instance each of GroupAdvisor and
ItemAdvisor are needed
• In the refactored design, these instances will
be static objects in the Customer class
38
Code for the recommend() Method in
the GroupAdvisor Class
• This is what the recommend() method looks like
in the GroupAdvisor class:
• public Firework recommend(Customer c)
• {
•
return (Firework) Rel8.advise(c);
• }
• By means of a wrapped call, the implementation
of the method translates from the advise()
interface of Rel8 to the recommend() interface of
Advisor
39
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.
40
• Challenge 23.2
• In addition to Strategy, what pattern appears
in the GroupAdvisor and ItemAdvisor classes?
41
• 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.
• Comment mode on:
• This wasn’t so hard—describing the wrapping
of the call as “translating” kind of gave it away
42
Code for the recommend() Method in
the PromotionAdvisor Class
• A PromotionAdvisor class is also needed, with
a recommend() method
• Most of the logic of the original code is moved
into the constructor for the new class
• If a promotion is on, then the promoted
instance variable of the class is initialized
43
• In addition to the recommend() method, there
is a hasItem() method which can be called to
see whether a promoted item is available
• Overall, the code is a bit messy because of the
class loader logic and the try/catch blocks
• The details of this technique will not be
covered since they are extraneous to the
design pattern
• The code is shown on the following overheads
44
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
public class PromotionAdvisor implements Advisor
{
private Firework promoted;
public PromotionAdvisor()
{
try
{
Properties p = new Properties();
p.load(ClassLoader.getSystemResourceAsStream("config/strategy.dat"));
String promotedFireworkName = p.getProperty("promote");
if (promotedFireworkName != null)
promoted = Firework.lookup(promotedFireworkName);
}
catch (Exception ignored)
{
// Resource not found or failed to load
promoted = null;
}
}
45
•
•
•
•
•
•
•
•
• }
public boolean hasItem()
{
return promoted != null;
}
public Firework recommend(Customer c)
{
return promoted;
}
46
Code for the recommend() Method in
the RandomAdvisor Class
• The RandomAdvisor class is simple
• Its code is shown on the following overhead
47
• public class RandomAdvisor implements Advisor
• {
•
public Firework recommend(Customer c)
•
{
•
return Firework.getRandom();
•
}
• }
48
Refactoring the Customer Class to Use
the Interface
• In order to make use of the recommend() method, a single instance
of each of the advisor classes may be needed
• The new customer class, Customer2, has these lines of code in it at
the top:
•
•
private static PromotionAdvisor promotionAdvisor =
new PromotionAdvisor();
•
•
private static GroupAdvisor groupAdvisor =
new GroupAdvisor();
•
•
private static ItemAdvisor itemAdvisor =
new ItemAdvisor();
•
•
private static RandomAdvisor randomAdvisor =
new RandomAdvisor();
49
• Customer2 also contains a method named
getAdvisor() for picking which kind of advisor
to use
• This code is organized around a sequence of
if/else if statements
• In other words, the logic for picking the
advisor replaces the earlier code which called
different strategies directly
50
• The book calls the approach used in the code
lazy-initialization
• It’s not lazy construction because one instance
of each kind of advisor has already been
created
• The point is that the value of the advisor
instance variable for a customer is only set at
the time that you try to acquire an advisor
• The code is shown on the following overhead
51
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
private Advisor getAdvisor()
{
if (advisor == null)
{
if (promotionAdvisor.hasItem())
advisor = promotionAdvisor;
else if (isRegistered())
advisor = groupAdvisor;
else if (isBigSpender())
advisor = itemAdvisor;
else
advisor = randomAdvisor;
}
return advisor;
}
52
• Challenge 23.3
• Write the new code for
Customer.getRecommended().
• Comment mode on:
• In other words, write the code for the new
getRecommended() method in the Customer2
class
• This code should rely on the advisor for the
customer, and a call to the recommend() method
on that advisor
53
• Solution 23.3
• Your code should look something like:
• public Firework getRecommended()
• {
•
return getAdvisor().recommend(this);
• }
54
• This is where it becomes blindingly apparent
that some of the code in the application is
simplified by the design.
• Dynamic binding determines which version of
recommend() will be used depending on the
type of advisor that was initialized earlier.
55
Comparing Strategy and State
• Consider the Strategy design pattern example
• The redesign ended with a recommend()
method implemented in several different
advisor classes
• The recommend() method is called in the
customer getRecommended() method
• Which version of recommend() is called
depends on polymorphism, the type of the
object it is called on
56
• Recall the State design pattern example
• It ended with a touch() method implemented
in several different state classes
• Which version of touch() was used depended
on the object that it was called on
• It is possible to argue that there is little
difference between the State and Strategy
design patterns
57
• At the macro level, structurally, at least, this is
the case
• If you compared the UML diagrams of the
relationships between classes in the two
patterns, they would be very similar
• This has also been apparent with some of the
patterns already considered
58
• The book argues that the critical difference is
that states and strategies have different
intents
• The difference isn’t just one of intent
• It’s clear from the problem domains that there
is a difference between transitioning between
states of doors and choosing among fireworks
to recommend
59
• The point of the touch() method was that calling
it in one state caused you to enter another
• Calling the recommend() method on a
GroupAdvisor object doesn’t somehow send the
application into a state where the current
ItemAdvisor is no longer applicable
• At the micro level, this is apparent in the design
and code
• The strategy pattern does not do the same thing
that the state pattern does
60
• With strategy, the application may choose among
different strategies based on various conditions
• With state, the client may take an action, but it
doesn’t explicitly choose a state
• The logic of the states themselves control the
transition from one to another
• The book concludes that in spite of their
structural similarity, State and Strategy are
different patterns
61
Comparing Strategy and Template
Method
• Recall the first Template Method design
pattern example
• The template was a sort() method in the
Arrays or Collections class
• What was stubbed in was the pairwise
comparison operation for elements of the
data structure
62
• The authors state that you might argue that
changing the pairwise comparison step
changes the strategy of sorting
• They illustrate this idea by suggesting that
sorting rockets by price rather than by thrust
would support a different marketing strategy
• Observe that the claim about strategy in this
argument is about something in the problem
domain, marketing, not in the code writing
63
• Challenge 23.4
• Provide an argument that the Arrays.sort()
method provides an example of Template
Method or that it is an example of Strategy.
• Comment mode on:
• It’s clear that the book thinks sorting is an
example of template, not strategy, since sorting
was covered in the template unit.
• I agree with its reasoning, as presented in the
second of the following arguments
64
• Solution 23.4
• Is a reusable sort routine an example of
Template Method or of Strategy?
• [See the following overheads.]
65
An Argument that Sorting is an
Example of the Strategy Design Pattern
• Template Method, according to the original
Design Patterns book, lets “subclasses” redefine
certain steps of an algorithm.
• But the Collections.sort() method doesn’t work
with subclasses; it uses a Comparator instance.
• Each instance of Comparator provides a new
method and thus a new algorithm and a new
strategy.
• The sort() method is a good example of Strategy.
66
An Argument that Sorting is an Example of
the Template Design Pattern
• There are many sorting algorithms, but
Collections.sort() uses only one (QuickSort).
• Changing the algorithm would mean changing to,
say, a heap sort or a bubble sort.
• The intent of Strategy is to let you plug in
different algorithms.
• That doesn’t happen here.
• The intent of Template Method is to let you plug
a step into an algorithm.
• That is precisely how the sort() method works.
67
• The book’s argument is good—but maybe not
entirely clear.
• The point is that at the macro level, a choice
among strategies would mean a choice between
different sorting algorithms
• At the micro level, choosing between pairwise
comparisons doesn’t change the overall strategy
• It is an example of applying the template pattern
68
Another Example
• As usual, there is another example on the
course Web page
• It involves cups and seeds
• It doesn’t illustrate anything new about the
pattern, so it will not be covered in class
• If you would like practice with the pattern you
can work the example as an exercise
69
UML for the Pattern
• The UML diagram given earlier is repeated on the
following overhead
• It is specific to the fireworks problem, but
otherwise it shows what the pattern is about
• It might be possible to make this and other
patterns clearer by including sequence diagrams
• It would show how the getRecommended()
method makes a call to the recommend() method
70
71
A UML Diagram for the Pattern from
Lasater
• Lasater’s UML diagram is given on the
following overhead
• It is useful, as usual, because it uses generic
names for the classes in the pattern
• This one is also useful because it shows that
you could use an abstract class just as easily as
you could use an interface when applying the
pattern
72
73
Summary
• Multiple strategies may appear in a single
method
• This can be an unwieldy design
• A solution is to implement each separate
strategy as a method of the same name in
different classes
• The individual implementations will be
simpler
74
• The original design would have logic to pick
one of the strategies
• The new design would also contain such logic
somewhere, but at least it is separated from
the implementations of the strategies
• The new logic will be based on which of the
strategy classes is constructed
• It would be reasonable to hold the strategy
object as a reference in a client class
75
• Then at the appropriate time, this object has the
strategy method called on it
• In other words, once the object choice is made,
the method choice is accomplished by
polymorphism
• The result of this kind of design is individual
pieces of code that are smaller, simpler, and
unified in purpose
• Overall, the design should be clearer, with
different strategies implemented in different
classes
76
The End
77