📄 pat5j.htm
字号:
<A NAME="auto1023"></A>
<P></P>
<A NAME="auto1024"></A>
<LI>concrete AbstractClass operations (i.e., operations that are
generally useful to subclasses);</LI>
<A NAME="auto1025"></A>
<P></P>
<A NAME="oper-primitive2"></A>
<LI>primitive operations (i.e., abstract operations);</LI>
<A NAME="auto1026"></A>
<P></P>
<A NAME="auto1027"></A>
<LI>factory methods (see <A HREF="pat3cfs.htm" tppabs="http://ultra/development/DesignPatterns/hires/pat3cfs.htm" TARGET="_mainDisplayFrame">Factory Method (107)</A>);
and</LI>
<A NAME="auto1028"></A>
<P></P>
<A NAME="auto1029"></A>
<LI><STRONG>hook operations</STRONG>, which provide default behavior that
subclasses can extend if necessary. A hook operation often does
nothing by default.</LI>
</UL>
<A NAME="auto1030"></A>
<P>It's important for template methods to specify which operations are
hooks (<EM>may</EM> be overridden) and which are abstract operations
(<EM>must</EM> be overridden). To reuse an abstract class effectively,
subclass writers must understand which operations are designed for
overriding.</P>
<A NAME="auto1031"></A>
<P>A subclass can <EM>extend</EM> a parent class operation's behavior by
overriding the operation and calling the parent operation explicitly:
<A NAME="auto1032"></A>
<PRE>
void DerivedClass::Operation () {
ParentClass::Operation();
// DerivedClass extended behavior
}
</PRE>
<A NAME="auto1033"></A>
<P>Unfortunately, it's easy to forget to call the inherited operation.
We can transform such an operation into a template method to give
the parent control over how subclasses extend it. The idea is to
call a hook operation from a template method in the parent class.
Then subclasses can then override this hook operation:</P>
<A NAME="auto1034"></A>
<PRE>
void ParentClass::Operation () {
// ParentClass behavior
HookOperation();
}
</PRE>
<A NAME="auto1035"></A>
<P><CODE>HookOperation</CODE> does nothing in <CODE>ParentClass</CODE>:</P>
<A NAME="auto1036"></A>
<PRE>
void ParentClass::HookOperation () { }
</PRE>
<A NAME="auto1037"></A>
<P>Subclasses override <CODE>HookOperation</CODE> to extend its
behavior:</P>
<A NAME="auto1038"></A>
<PRE>
void DerivedClass::HookOperation () {
// derived class extension
}
</PRE>
<A NAME="implementation"></A>
<H2><A HREF="#samplecode"><IMG SRC="down3.gif" tppabs="http://ultra/development/DesignPatterns/hires/gifsb/down3.gif" BORDER=0 ALT="next:
Sample Code"></A> Implementation</H2>
<A NAME="auto1039"></A>
<P>Three implementation issues are worth noting:</P>
<OL>
<A NAME="auto1040"></A>
<LI><EM>Using C++ access control.</EM>
In C++, the primitive operations that a template method calls can be
declared protected members. This ensures that they are only called by
the template method. Primitive operations that <EM>must</EM> be overridden are
declared pure virtual. The template method itself should not be
overridden; therefore you can make the template method a nonvirtual
member function.</LI>
<A NAME="auto1041"></A>
<P></P>
<A NAME="auto1042"></A>
<LI><EM>Minimizing primitive operations.</EM>
An important goal in designing template methods is to minimize the
number of primitive operations that a subclass must override to flesh
out the algorithm. The more operations that need overriding, the more
tedious things get for clients.</LI>
<A NAME="auto1043"></A>
<P></P>
<A NAME="templ-naming"></A>
<LI><EM>Naming conventions.</EM>
You can identify the operations that should be overridden by adding a
prefix to their names. For example, the MacApp framework for Macintosh
applications [<A HREF="bibfs.htm#macapp" tppabs="http://ultra/development/DesignPatterns/hires/bibfs.htm#macapp" TARGET="_mainDisplayFrame">App89</A>] prefixes template method names with "Do-":
"DoCreateDocument", "DoRead", and so forth.</LI>
</OL>
<A NAME="samplecode"><A>
<H2><A HREF="#knownuses"><IMG SRC="down3.gif" tppabs="http://ultra/development/DesignPatterns/hires/gifsb/down3.gif" BORDER=0 ALT="next:
Known Uses"></A> Sample Code</H2>
<A NAME="auto1044"></A>
<P>The following C++ example shows how a parent class can enforce an
invariant for its subclasses. The example comes from NeXT's
AppKit [<A HREF="bibfs.htm#NeXT_AppKit" tppabs="http://ultra/development/DesignPatterns/hires/bibfs.htm#NeXT_AppKit" TARGET="_mainDisplayFrame">Add94</A>]. Consider a class <CODE>View</CODE> that supports
drawing on the screen. <CODE>View</CODE> enforces the invariant that its
subclasses can draw into a view only after it becomes the "focus,"
which requires certain drawing state (for example, colors and fonts) to
be set up properly.</P>
<A NAME="auto1045"></A>
<P>We can use a <CODE>Display</CODE> template method to set up this state.
<CODE>View</CODE> defines two concrete operations,
<CODE>SetFocus</CODE> and <CODE>ResetFocus</CODE>, that set up and clean up
the drawing state, respectively. <CODE>View</CODE>'s <CODE>DoDisplay</CODE>
hook operation performs the actual drawing. <CODE>Display</CODE> calls
<CODE>SetFocus</CODE> before <CODE>DoDisplay</CODE> to set up the drawing
state; <CODE>Display</CODE> calls <CODE>ResetFocus</CODE> afterwards to
release the drawing state.</P>
<A NAME="auto1046"></A>
<PRE>
void View::Display () {
SetFocus();
DoDisplay();
ResetFocus();
}
</PRE>
<A NAME="auto1047"></A>
<P>To maintain the invariant, the <CODE>View</CODE>'s clients always call
<CODE>Display</CODE>, and <CODE>View</CODE> subclasses always override
<CODE>DoDisplay</CODE>.</P>
<A NAME="auto1048"></A>
<P><CODE>DoDisplay</CODE> does nothing in <CODE>View</CODE>:</P>
<A NAME="auto1049"></A>
<PRE>
void View::DoDisplay () { }
</PRE>
<A NAME="auto1050"></A>
<P>Subclasses override it to add their specific drawing behavior:</P>
<A NAME="auto1051"></A>
<PRE>
void MyView::DoDisplay () {
// render the view's contents
}
</PRE>
<A NAME="knownuses"><A>
<H2><A HREF="#relatedpatterns"><IMG SRC="down3.gif" tppabs="http://ultra/development/DesignPatterns/hires/gifsb/down3.gif" BORDER=0
ALT="next: Related Patterns"></A> Known Uses</H2>
<A NAME="auto1052"></A>
<P>Template methods are so fundamental that they can be found in almost
every abstract class. Wirfs-Brock et al. [<A HREF="bibfs.htm#doosw_www" tppabs="http://ultra/development/DesignPatterns/hires/bibfs.htm#doosw_www" TARGET="_mainDisplayFrame">WBWW90,</A>
<A HREF="bibfs.htm#wirfs-brock_cacm" tppabs="http://ultra/development/DesignPatterns/hires/bibfs.htm#wirfs-brock_cacm" TARGET="_mainDisplayFrame"> WBJ90</A>] provide a good overview and
discussion of template methods.</P>
<A NAME="relatedpatterns"></A>
<H2><A HREF="#last"><IMG SRC="down3.gif" tppabs="http://ultra/development/DesignPatterns/hires/gifsb/down3.gif" BORDER=0 ALT="next:
navigation"></A> Related Patterns</H2>
<A NAME="auto1053"></A>
<P><A HREF="pat3cfs.htm" tppabs="http://ultra/development/DesignPatterns/hires/pat3cfs.htm" TARGET="_mainDisplayFrame">Factory Methods (107)</A>
are often called by template methods. In the Motivation example,
the factory method DoCreateDocument is called by the template method
OpenDocument.</P>
<A NAME="auto1054"></A>
<P><A HREF="pat5ifs.htm" tppabs="http://ultra/development/DesignPatterns/hires/pat5ifs.htm" TARGET="_mainDisplayFrame">Strategy (315)</A>:
Template methods use inheritance to vary part of an algorithm.
Strategies use delegation to vary the entire algorithm.</P>
<A NAME="last"></A>
<P><A HREF="#intent"><IMG SRC="up3.gif" tppabs="http://ultra/development/DesignPatterns/hires/gifsb/up3.gif" BORDER=0></A><BR>
<A HREF="pat5kfs.htm" tppabs="http://ultra/development/DesignPatterns/hires/pat5kfs.htm" TARGET="_mainDisplayFrame"><IMG SRC="rightar3.gif" tppabs="http://ultra/development/DesignPatterns/hires/gifsb/rightar3.gif"
ALIGN=TOP BORDER=0></A> <A HREF="pat5kfs.htm" tppabs="http://ultra/development/DesignPatterns/hires/pat5kfs.htm"
TARGET="_mainDisplayFrame">Visitor</A><BR>
<A HREF="pat5ifs.htm" tppabs="http://ultra/development/DesignPatterns/hires/pat5ifs.htm" TARGET="_mainDisplayFrame"><IMG SRC="leftarr3.gif" tppabs="http://ultra/development/DesignPatterns/hires/gifsb/leftarr3.gif"
ALIGN=TOP BORDER=0></A> <A HREF="pat5ifs.htm" tppabs="http://ultra/development/DesignPatterns/hires/pat5ifs.htm"
TARGET="_mainDisplayFrame">Strategy</A>
</P>
</BODY>
</HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -