📄 pat5i.htm
字号:
<HTML>
<HEAD><TITLE>Strategy</TITLE></HEAD>
<BODY BGCOLOR = #FFFFFF>
<A NAME="top"></A>
<A NAME="Strategy"></A>
<A NAME="intent"></A>
<H2><A HREF="#alsoknownas"><IMG SRC="gifsb/down3.gif" BORDER=0></A> Intent</H2>
<A NAME="auto1000"></A>
<P>Define a family of algorithms, encapsulate each one, and make them
interchangeable. Strategy lets the algorithm vary independently from
clients that use it.</P>
<A NAME="alsoknownas"><A>
<H2><A HREF="#motivation"><IMG SRC="gifsb/down3.gif" BORDER=0></A> Also Known As</H2>
<A NAME="auto1001"></A>
<P>Policy</P>
<A NAME="motivation"></A>
<H2><A HREF="#applicability"><IMG SRC="gifsb/down3.gif" BORDER=0></A> Motivation</H2>
<A NAME="auto1002"></A>
<P>Many algorithms exist for breaking a stream of text into lines.
Hard-wiring all such algorithms into the classes that require them
isn't desirable for several reasons:</P>
<UL>
<A NAME="auto1003"></A>
<LI>Clients that need linebreaking get more complex if they include
the linebreaking code. That makes clients bigger and harder to
maintain, especially if they support multiple linebreaking algorithms.</LI>
<A NAME="auto1004"></A>
<P></P>
<A NAME="auto1005"></A>
<LI>Different algorithms will be appropriate at different times. We don't
want to support multiple linebreaking algorithms if we don't use them
all.</LI>
<A NAME="auto1006"></A>
<P></P>
<A NAME="auto1007"></A>
<LI>It's difficult to add new algorithms and vary existing ones when
linebreaking is an integral part of a client.</LI>
</UL>
<A NAME="def-strategy"></A>
<P>We can avoid these problems by defining classes that encapsulate
different linebreaking algorithms. An algorithm that's encapsulated in
this way is called a <STRONG>strategy</STRONG>.</P>
<A NAME="315c"></A>
<P ALIGN=CENTER><IMG SRC="Pictures/strat011.gif"></P>
<A NAME="compositor"></A>
<P>Suppose a Composition class is responsible for maintaining and
updating the linebreaks of text displayed in a text viewer.
Linebreaking strategies aren't implemented by the class Composition.
Instead, they are implemented separately by subclasses of the abstract
Compositor class. Compositor subclasses implement different strategies:</P>
<UL>
<A NAME="simplecompositor"></A>
<LI><STRONG>SimpleCompositor</STRONG>
implements a simple strategy that determines linebreaks one at a
time.</LI>
<A NAME="auto1008"></A>
<P></P>
<A NAME="tex-comp"></A>
<LI><STRONG>TeXCompositor</STRONG>
implements the TeX algorithm for finding linebreaks. This strategy
tries to optimize linebreaks globally, that is, one paragraph at a
time.</LI>
<A NAME="auto1009"></A>
<P></P>
<A NAME="auto1010"></A>
<LI><STRONG>ArrayCompositor</STRONG>
implements a strategy that selects breaks so that each row has a fixed
number of items. It's useful for breaking a collection of icons into
rows, for example.</LI>
</UL>
<A NAME="auto1011"></A>
<P>A Composition maintains a reference to a Compositor object. Whenever a
Composition reformats its text, it forwards this responsibility to its
Compositor object. The client of Composition specifies which
Compositor should be used by installing the Compositor it desires into
the Composition.</P>
<A NAME="applicability"></A>
<H2><A HREF="#structure"><IMG SRC="gifsb/down3.gif" BORDER=0></A> Applicability</H2>
<A NAME="auto1012"></A>
<P>Use the Strategy pattern when</P>
<UL>
<A NAME="auto1013"></A>
<LI>many related classes differ only in their behavior. Strategies
provide a way to configure a class with one of many behaviors.</LI>
<A NAME="auto1014"></A>
<P></P>
<A NAME="auto1015"></A>
<LI>you need different variants of an algorithm. For example, you might define
algorithms reflecting different space/time trade-offs.
Strategies can be used when these variants are implemented as a class
hierarchy of algorithms [<A HREF="vfs.htm?doc=bib-0.htm&fid=bb&hid=halbert-obrien" TARGET="_mainDisplayFrame">HO87</A>].</LI>
<A NAME="auto1016"></A>
<P></P>
<A NAME="auto1017"></A>
<LI>an algorithm uses data that clients shouldn't know about. Use the
Strategy pattern to avoid exposing complex, algorithm-specific data
structures.</LI>
<A NAME="auto1018"></A>
<P></P>
<A NAME="auto1019"></A>
<LI>a class defines many behaviors, and these appear as multiple
conditional statements in its operations. Instead of many
conditionals, move related conditional branches into their own
Strategy class.</LI>
</UL>
<A NAME="structure"></A>
<H2><A HREF="#participants"><IMG SRC="gifsb/down3.gif" BORDER=0></A>
Structure</H2>
<A NAME="strat-316c"></A>
<P ALIGN=CENTER><IMG SRC="Pictures/strategy.gif"></P>
<A NAME="participants"></A>
<H2><A HREF="#collaborations"><IMG SRC="gifsb/down3.gif" BORDER=0></A>
Participants</H2>
<UL>
<A NAME="auto1020"></A>
<LI><B>Strategy</B> (Compositor)</LI>
<A NAME="auto1021"></A>
<P></P>
<UL>
<A NAME="auto1022"></A>
<LI>declares an interface common to all supported algorithms.
Context uses this interface to call the
algorithm defined by a ConcreteStrategy.</LI>
</UL>
<A NAME="auto1023"></A>
<P></P>
<A NAME="auto1024"></A>
<LI><B>ConcreteStrategy</B> (SimpleCompositor, TeXCompositor,
ArrayCompositor)</LI>
<A NAME="auto1025"></A>
<P></P>
<UL>
<A NAME="auto1026"></A>
<LI>implements the algorithm using the Strategy interface.</LI>
</UL>
<A NAME="auto1027"></A>
<P></P>
<A NAME="auto1028"></A>
<LI><B>Context</B> (Composition)
<A NAME="auto1029"></A>
<P></P>
<UL>
<A NAME="auto1030"></A>
<LI>is configured with a ConcreteStrategy object.</LI>
<A NAME="auto1031"></A>
<P><!-- extra space --></P>
<A NAME="auto1032"></A>
<LI>maintains a reference to a Strategy object.</LI>
<A NAME="auto1033"></A>
<P><!-- extra space --></P>
<A NAME="auto1034"></A>
<LI>may define an interface that lets Strategy access its data.</LI>
</UL>
</UL>
<A NAME="collaborations"></A>
<H2><A HREF="#consequences"><IMG SRC="gifsb/down3.gif" BORDER=0></A> Collaborations</H2>
<UL>
<A NAME="auto1035"></A>
<LI>Strategy and Context interact to implement the chosen algorithm. A
context may pass all data required by the algorithm to the strategy
when the algorithm is called. Alternatively, the context can pass
itself as an argument to Strategy operations. That lets the strategy
call back on the context as required.</LI>
<A NAME="auto1036"></A>
<P></P>
<A NAME="auto1037"></A>
<LI>A context forwards requests from its clients to its strategy. Clients
usually create and pass a ConcreteStrategy object to the context;
thereafter, clients interact with the context exclusively. There is
often a family of ConcreteStrategy classes for a client to choose
from.</LI>
</UL>
<A NAME="consequences"></A>
<H2><A HREF="#implementation"><IMG SRC="gifsb/down3.gif" BORDER=0></A> Consequences</H2>
<A NAME="auto1038"></A>
<P>The Strategy pattern has the following benefits and drawbacks:</P>
<OL>
<A NAME="families"></A>
<LI><EM>Families of related algorithms.</EM>
Hierarchies of Strategy classes define a family of algorithms or
behaviors for contexts to reuse. Inheritance can
help factor out common functionality of the algorithms.</LI>
<A NAME="auto1039"></A>
<P></P>
<A NAME="auto1040"></A>
<LI><EM>An alternative to subclassing.</EM>
Inheritance offers another way to support a variety of algorithms or
behaviors. You can subclass a Context class directly to give it
different behaviors. But this hard-wires the behavior into Context.
It mixes the algorithm implementation with Context's, making Context
harder to understand, maintain, and extend. And you can't vary the
algorithm dynamically. You wind up with many related classes whose
only difference is the algorithm or behavior they employ.
Encapsulating the algorithm in separate Strategy classes lets you vary
the algorithm independently of its context, making it easier to
switch, understand, and extend.</LI>
<A NAME="auto1041"></A>
<P></P>
<A NAME="auto1042"></A>
<LI><EM>Strategies eliminate conditional statements.</EM>
The Strategy pattern offers an alternative to conditional statements for
selecting desired behavior. When different behaviors are lumped into one
class, it's hard to avoid using conditional statements to select the
right behavior. Encapsulating the behavior in separate Strategy classes
eliminates these conditional statements.
<A NAME="auto1043"></A>
<P>For example, without strategies, the code for breaking
text into lines could look like
<A NAME="auto1044"></A>
<PRE>
void Composition::Repair () {
switch (_breakingStrategy) {
case SimpleStrategy:
ComposeWithSimpleCompositor();
break;
case TeXStrategy:
ComposeWithTeXCompositor();
break;
// ...
}
// merge results with existing composition, if necessary
}
</PRE>
<A NAME="auto1045"></A>
<P>The Strategy pattern eliminates this case statement by delegating the
linebreaking task to a Strategy object:</P>
<A NAME="auto1046"></A>
<PRE>
void Composition::Repair () {
_compositor->Compose();
// merge results with existing composition, if necessary
}
</PRE>
<A NAME="auto1047"></A>
<P>Code containing many conditional statements often indicates
the need to apply the Strategy pattern.</P>
</LI>
<A NAME="auto1048"></A>
<P></P>
<A NAME="auto1049"></A>
<LI><EM>A choice of implementations.</EM>
Strategies can provide different implementations of the <EM>same</EM>
behavior. The client can choose among strategies with different
time and space trade-offs.</LI>
<A NAME="auto1050"></A>
<P></P>
<A NAME="auto1051"></A>
<LI><EM>Clients must be aware of different Strategies.</EM>
The pattern has a potential drawback in that a client must understand
how Strategies differ before it can select the appropriate one.
Clients might be exposed to implementation issues. Therefore you
should use the Strategy pattern only when the variation in behavior is
relevant to clients.</LI>
<A NAME="auto1052"></A>
<P></P>
<A NAME="auto1053"></A>
<LI><EM>Communication overhead between Strategy and Context.</EM>
The Strategy interface is shared by all ConcreteStrategy classes
whether the algorithms they implement are trivial or complex. Hence
it's likely that some ConcreteStrategies won't use all the information
passed to them through this interface; simple ConcreteStrategies may
use none of it! That means there will be times when the context
creates and initializes parameters that never get used. If this is an
issue, then you'll need tighter coupling between Strategy and Context.</LI>
<A NAME="auto1054"></A>
<P></P>
<A NAME="auto1055"></A>
<LI><EM>Increased number of objects.</EM>
Strategies increase the number of objects in an application. Sometimes
you can reduce this overhead by implementing strategies as stateless
objects that contexts can share. Any residual state is maintained by the
context, which passes it in each request to the Strategy object. Shared
strategies should not maintain state across invocations. The
<A HREF="pat4ffs.htm" TARGET="_mainDisplayFrame">Flyweight (<As+HREF="#Flyweight">195</A>) pattern describes this approach in more
detail.</LI>
</OL>
<A NAME="implementation"></A>
<H2><A HREF="#samplecode"><IMG SRC="gifsb/down3.gif" BORDER=0></A> Implementation</H2>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -