📄 pat3c.htm
字号:
<SCRIPT>
function setFocus() {
if ((navigator.appName != "Netscape") && (parseFloat(navigator.appVersion) == 2)) {
return;
} else {
self.focus();
}
}
</SCRIPT><HTML><HEAD><TITLE>Factory Method</TITLE></HEAD><BODY BGCOLOR = #FFFFFF TEXT = #000000
onLoad="setFocus()";><A NAME="top"></A><A NAME="FactoryMethod"></A><A NAME="intent"></A><H2><A HREF="#alsoknownas"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Also Known As"></A> Intent</H2> <A NAME="auto1000"></A><P>Define an interface for creating an object, but let subclasses decidewhich class to instantiate. Factory Method lets a class deferinstantiation to subclasses.</P><A NAME="alsoknownas"><A><H2><A HREF="#motivation"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Motivation"></A> Also Known As</H2> <A NAME="auto1001"></A><P>Virtual Constructor</P><A NAME="motivation"></A><H2><A HREF="#applicability"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Applicability"></A> Motivation</H2> <A NAME="auto1002"></A><P>Frameworks use abstract classes to define and maintain relationshipsbetween objects. A framework is often responsible for creating theseobjects as well.</P><A NAME="app"></A><P>Consider a framework for applications that can present multipledocuments to the user. Two key abstractions in this framework are theclasses Application and Document. Both classes are abstract, andclients have to subclass them to realize their application-specificimplementations. To create a drawing application, for example, wedefine the classes DrawingApplication and DrawingDocument. TheApplication class is responsible for managing Documents and willcreate them as required—when the user selects Open or New from amenu, for example.</P><A NAME="auto1003"></A><P>Because the particular Document subclass to instantiate isapplication-specific, the Application class can't predict thesubclass of Document to instantiate—the Application class onlyknows <EM>when</EM> a new document should be created, not <EM>whatkind</EM> of Document to create. This creates a dilemma: Theframework must instantiate classes, but it only knows about abstractclasses, which it cannot instantiate.</P><A NAME="auto1004"></A><P>The Factory Method pattern offers a solution. It encapsulates theknowledge of which Document subclass to create and moves thisknowledge out of the framework.</P><A NAME="107c"></A><P ALIGN=CENTER><IMG SRC="Pictures/fmeth049.gif"></P><A NAME="auto1005"></A><P>Application subclasses redefine an abstract CreateDocument operationon Application to return the appropriate Document subclass. Once anApplication subclass is instantiated, it can then instantiateapplication-specific Documents without knowing their class. We callCreateDocument a <STRONG>factory method</STRONG> because it's responsiblefor "manufacturing" an object.</P><A NAME="applicability"></A><H2><A HREF="#structure"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Structure"></A> Applicability</H2> <A NAME="auto1006"></A><P>Use the Factory Method pattern when</P><UL><A NAME="auto1007"></A><LI>a class can't anticipate the class of objects it must create.</LI><A NAME="auto1008"></A><P></P><A NAME="auto1009"></A><LI>a class wants its subclasses to specify the objects it creates.</LI><A NAME="auto1010"></A><P></P><A NAME="auto1011"></A><LI>classes delegate responsibility to one of several helper subclasses,and you want to localize the knowledge of which helper subclass is thedelegate.</LI></UL><A NAME="structure"></A><H2><A HREF="#participants"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Participants"></A> Structure</H2> <P ALIGN=CENTER><IMG SRC="Pictures/fmethod.gif"></P><A NAME="participants"></A><H2><A HREF="#collaborations"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Collaborations"></A> Participants</H2><UL><A NAME="prod-part-facmeth"></A><LI><B>Product</B> (Document)<A NAME="auto1012"></A><P></P> <UL> <A NAME="auto1013"></A><LI>defines the interface of objects the factory method creates.</LI> </UL><A NAME="auto1014"></A><P></P><A NAME="auto1015"></A><LI><B>ConcreteProduct</B> (MyDocument)<A NAME="auto1016"></A><P></P> <UL> <A NAME="auto1017"></A><LI>implements the Product interface.</LI> </UL><A NAME="auto1018"></A><P></P><A NAME="auto1019"></A><LI><B>Creator</B> (Application)<A NAME="auto1020"></A><P></P> <UL> <A NAME="auto1021"></A><LI>declares the factory method, which returns an object of type Product. Creator may also define a default implementation of the factory method that returns a default ConcreteProduct object.</LI> <A NAME="auto1022"></A><P><!-- extra space --></P> <A NAME="auto1023"></A><LI>may call the factory method to create a Product object.</LI> </UL><A NAME="auto1024"></A><P></P><A NAME="auto1025"></A><LI><B>ConcreteCreator</B> (MyApplication)<A NAME="auto1026"></A><P></P> <UL> <A NAME="auto1027"></A><LI>overrides the factory method to return an instance of a ConcreteProduct.</LI> </UL></UL><A NAME="collaborations"></A><H2><A HREF="#consequences"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Consequences"></A> Collaborations</H2><UL><A NAME="auto1028"></A><LI>Creator relies on its subclasses to define the factory method sothat it returns an instance of the appropriate ConcreteProduct.</LI></UL><A NAME="consequences"></A><H2><A HREF="#implementation"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Implementation"></A> Consequences</H2> <A NAME="auto1029"></A><P>Factory methods eliminate the need to bind application-specificclasses into your code. The code only deals with the Productinterface; therefore it can work with any user-definedConcreteProduct classes.</P><A NAME="auto1030"></A><P>A potential disadvantage of factory methods is that clients might haveto subclass the Creator class just to create a particularConcreteProduct object. Subclassing is fine when the client has tosubclass the Creator class anyway, but otherwise the client now mustdeal with another point of evolution.</P><A NAME="auto1031"></A><P>Here are two additional consequences of the Factory Method pattern:</P><OL><A NAME="auto1032"></A><LI><EM>Provides hooks for subclasses.</EM>Creating objects inside a class with a factory method is always moreflexible than creating an object directly. Factory Method givessubclasses a hook for providing an extended version of an object.<A NAME="auto1033"></A><P>In the Document example, the Document class could define a factorymethod called CreateFileDialog that creates a default file dialogobject for opening an existing document. A Document subclass candefine an application-specific file dialog by overriding this factorymethod. In this case the factory method is not abstract but providesa reasonable default implementation.</LI><A NAME="auto1034"></A><P></P><A NAME="auto1035"></A><LI><EM>Connects parallel class hierarchies.</EM>In the examples we've considered so far, the factory method is onlycalled by Creators. But this doesn't have to be the case;clients can find factory methods useful, especially in the case ofparallel class hierarchies.<A NAME="auto1036"></A><P>Parallel class hierarchies result when a class delegates some of itsresponsibilities to a separate class. Consider graphical figures thatcan be manipulated interactively; that is, they can be stretched,moved, or rotated using the mouse. Implementing such interactionsisn't always easy. It often requires storing and updating informationthat records the state of the manipulation at a given time. Thisstate is needed only during manipulation; therefore it needn't be keptin the figure object. Moreover, different figures behave differentlywhen the user manipulates them. For example, stretching a line figuremight have the effect of moving an endpoint, whereas stretching a textfigure may change its line spacing.</P><A NAME="manip"></A><P>With these constraints, it's better to use a separate Manipulatorobject that implements the interaction and keeps track of anymanipulation-specific state that's needed. Different figures will usedifferent Manipulator subclasses to handle particular interactions.The resulting Manipulator class hierarchy parallels (at leastpartially) the Figure class hierarchy:</P><A NAME="fmethod-eg2"></A><P ALIGN=CENTER><IMG SRC="Pictures/fmeth048.gif"></P><A NAME="auto1037"></A><P>The Figure class provides a CreateManipulator factory method that letsclients create a Figure's corresponding Manipulator. Figure subclassesoverride this method to return an instance of the Manipulator subclassthat's right for them. Alternatively, the Figure class may implementCreateManipulator to return a default Manipulator instance, and Figuresubclasses may simply inherit that default. The Figure classes thatdo so need no corresponding Manipulator subclass—hence thehierarchies are only partially parallel.</P><A NAME="auto1038"></A><P>Notice how the factory method defines the connection between the twoclass hierarchies. It localizes knowledge of which classes belongtogether.</P></OL><A NAME="implementation"></A><H2><A HREF="#samplecode"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Sample Code"></A> Implementation</H2> <A NAME="auto1039"></A><P>Consider the following issues when applying the Factory Method pattern:</P><OL><A NAME="auto1040"></A><LI><EM>Two major varieties.</EM>The two main variations of the Factory Method pattern are (1) the casewhen the Creator class is an abstract class and does not provide animplementation for the factory method it declares, and (2) the casewhen the Creator is a concrete class and provides a defaultimplementation for the factory method. It's also possible to have anabstract class that defines a default implementation, but this is lesscommon.<A NAME="auto1041"></A><P>The first case <EM>requires</EM> subclasses to define an implementation,because there's no reasonable default. It gets around the dilemma ofhaving to instantiate unforeseeable classes. In the second case, theconcrete Creator uses the factory method primarily for flexibility.It's following a rule that says, "Create objects in a separateoperation so that subclasses can override the way they're created."This rule ensures that designers of subclasses can change the class ofobjects their parent class instantiates if necessary.</LI><A NAME="auto1042"></A><P></P><A NAME="fact-param-prod"></A><LI><EM>Parameterized factory methods.</EM>Another variation on the pattern lets the factory method create <EM>multiple</EM> kinds of products. The factory method takes a parameterthat identifies the kind of object to create. All objects the factorymethod creates will share the Product interface. In the Documentexample, Application might support different kinds of Documents. Youpass CreateDocument an extra parameter to specify the kind of documentto create.<A NAME="unidraw-use-factmeth"></A><P>The Unidraw graphical editing framework [<A HREF="bibfs.htm#unidraw_framework" TARGET="_mainDisplayFrame">VL90</A>] usesthis approach for reconstructing objects saved on disk. Unidrawdefines a <CODE>Creator</CODE> class with a factory method<CODE>Create</CODE> that takes a class identifier as an argument. Theclass identifier specifies the class to instantiate. When Unidrawsaves an object to disk, it writes out the class identifier first andthen its instance variables. When it reconstructs the object fromdisk, it reads the class identifier first.</P><A NAME="auto1043"></A><P>Once the class identifier is read, the framework calls<CODE>Create</CODE>, passing the identifier as the parameter.<CODE>Create</CODE> looks up the constructor for the corresponding classand uses it to instantiate the object. Last, <CODE>Create</CODE> callsthe object's <CODE>Read</CODE> operation, which reads the remaininginformation on the disk and initializes the object's instancevariables.</P><A NAME="auto1044"></A><P>A parameterized factory method has the following general form, where<CODE>MyProduct</CODE> and <CODE>YourProduct</CODE> are subclasses of<CODE>Product</CODE>:<A NAME="auto1045"></A><PRE> class Creator { public: virtual Product* Create(ProductId); }; Product* Creator::Create (ProductId id) { if (id == MINE) return new MyProduct; if (id == YOURS) return new YourProduct; // repeat for remaining products... return 0; }</PRE><A NAME="auto1047"></A><P>Overriding a parameterized factory method lets you easily andselectively extend or change the products that a Creator produces. Youcan introduce new identifiers for new kinds of products, or you can
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -