📄 chap11.htm
字号:
<font color=#0000ff>void</font> erase() { cout << <font color=#004488>"Square::erase\n"</font>; }
~Square() { cout << <font color=#004488>"Square::~Square\n"</font>; }
};
Shape* Shape::factory(string type)
<font color=#0000ff>throw</font>(Shape::BadShapeCreation) {
<font color=#0000ff>if</font>(type == <font color=#004488>"Circle"</font>) <font color=#0000ff>return</font> <font color=#0000ff>new</font> Circle;
<font color=#0000ff>if</font>(type == <font color=#004488>"Square"</font>) <font color=#0000ff>return</font> <font color=#0000ff>new</font> Square;
<font color=#0000ff>throw</font> BadShapeCreation(type);
}
<font color=#0000ff>char</font>* shlist[] = { <font color=#004488>"Circle"</font>, <font color=#004488>"Square"</font>, <font color=#004488>"Square"</font>,
<font color=#004488>"Circle"</font>, <font color=#004488>"Circle"</font>, <font color=#004488>"Circle"</font>, <font color=#004488>"Square"</font>, <font color=#004488>""</font> };
<font color=#0000ff>int</font> main() {
vector<Shape*> shapes;
<font color=#0000ff>try</font> {
<font color=#0000ff>for</font>(<font color=#0000ff>char</font>** cp = shlist; **cp; cp++)
shapes.push_back(Shape::factory(*cp));
} <font color=#0000ff>catch</font>(Shape::BadShapeCreation e) {
cout << e.what() << endl;
<font color=#0000ff>return</font> 1;
}
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < shapes.size(); i++) {
shapes[i]->draw();
shapes[i]->erase();
}
purge(shapes);
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>factory( )</B> takes an
argument that allows it to determine what type of <B>Shape</B> to create; it
happens to be a <B>string</B> in this case but it could be any set of data. The
<B>factory( )</B> is now the only other code in the system that needs to be
changed when a new type of <B>Shape </B>is added (the initialization data for
the objects will presumably come from somewhere outside the system, and not be a
hard-coded array as in the above example).</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">To ensure that the creation can only
happen in the <B>factory( )</B>, the constructors for the specific types of
<B>Shape</B> are made <B>private</B>, and <B>Shape</B> is declared a
<B>friend</B> so that <B>factory( )</B> has access to the constructors (you
could also declare only <B>Shape::factory( )</B> to be a <B>friend</B>, but
it seems reasonably harmless to declare the entire base class as a
<B>friend</B>).</FONT><A NAME="_Toc519042124"></A><BR></P></DIV>
<A NAME="Heading334"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Polymorphic factories</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>static factory( )</B> method
in the previous example forces all the creation operations to be focused in one
spot, to that’s the only place you need to change the code. This is
certainly a reasonable solution, as it throws a box around the process of
creating objects. However, the <I>Design Patterns</I> book emphasizes that the
reason for the <I>Factory Method</I> pattern is so that different types of
factories can be subclassed from the basic factory (the above design is
mentioned as a special case). However, the book does not provide an example, but
instead just repeats the example used for the <I>Abstract Factory</I>. Here is
<B>ShapeFactory1.cpp</B> modified so the factory methods are in a separate class
as virtual functions:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C11:ShapeFactory2.cpp</font>
<font color=#009900>// Polymorphic factory methods</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
#include <font color=#004488>"..</font><font color=#004488>/purge.h"</font>
#include <iostream>
#include <string>
#include <exception>
#include <vector>
#include <map>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#0000ff>class</font> Shape {
<font color=#0000ff>public</font>:
<font color=#0000ff>virtual</font> <font color=#0000ff>void</font> draw() = 0;
<font color=#0000ff>virtual</font> <font color=#0000ff>void</font> erase() = 0;
<font color=#0000ff>virtual</font> ~Shape() {}
};
<font color=#0000ff>class</font> ShapeFactory {
<font color=#0000ff>virtual</font> Shape* create() = 0;
<font color=#0000ff>static</font> map<string, ShapeFactory*> factories;
<font color=#0000ff>public</font>:
<font color=#0000ff>virtual</font> ~ShapeFactory() {}
<font color=#0000ff>friend</font> <font color=#0000ff>class</font> ShapeFactoryInitializer;
<font color=#0000ff>class</font> BadShapeCreation : <font color=#0000ff>public</font> exception {
string reason;
<font color=#0000ff>public</font>:
BadShapeCreation(string type) {
reason = <font color=#004488>"Cannot create type "</font> + type;
}
~BadShapeCreation() <font color=#0000ff>throw</font>() {}
<font color=#0000ff>const</font> <font color=#0000ff>char</font> *what() <font color=#0000ff>const</font> <font color=#0000ff>throw</font>() {
<font color=#0000ff>return</font> reason.c_str();
}
};
<font color=#0000ff>static</font> Shape*
createShape(string id) <font color=#0000ff>throw</font>(BadShapeCreation){
<font color=#0000ff>if</font>(factories.find(id) != factories.end())
<font color=#0000ff>return</font> factories[id]->create();
<font color=#0000ff>else</font>
<font color=#0000ff>throw</font> BadShapeCreation(id);
}
};
<font color=#009900>// Define the static object:</font>
map<string, ShapeFactory*>
ShapeFactory::factories;
<font color=#0000ff>class</font> Circle : <font color=#0000ff>public</font> Shape {
Circle() {} <font color=#009900>// Private constructor</font>
<font color=#0000ff>public</font>:
<font color=#0000ff>void</font> draw() { cout << <font color=#004488>"Circle::draw\n"</font>; }
<font color=#0000ff>void</font> erase() { cout << <font color=#004488>"Circle::erase\n"</font>; }
~Circle() { cout << <font color=#004488>"Circle::~Circle\n"</font>; }
<font color=#0000ff>private</font>:
<font color=#0000ff>friend</font> <font color=#0000ff>class</font> ShapeFactoryInitializer;
<font color=#0000ff>class</font> Factory;
<font color=#0000ff>friend</font> <font color=#0000ff>class</font> Factory;
<font color=#0000ff>class</font> Factory : <font color=#0000ff>public</font> ShapeFactory {
<font color=#0000ff>public</font>:
Shape* create() { <font color=#0000ff>return</font> <font color=#0000ff>new</font> Circle; }
<font color=#0000ff>friend</font> <font color=#0000ff>class</font> ShapeFactoryInitializer;
};
};
<font color=#0000ff>class</font> Square : <font color=#0000ff>public</font> Shape {
Square() {}
<font color=#0000ff>public</font>:
<font color=#0000ff>void</font> draw() { cout << <font color=#004488>"Square::draw\n"</font>; }
<font color=#0000ff>void</font> erase() { cout << <font color=#004488>"Square::erase\n"</font>; }
~Square() { cout << <font color=#004488>"Square::~Square\n"</font>; }
<font color=#0000ff>private</font>:
<font color=#0000ff>friend</font> <font color=#0000ff>class</font> ShapeFactoryInitializer;
<font color=#0000ff>class</font> Factory;
<font color=#0000ff>friend</font> <font color=#0000ff>class</font> Factory;
<font color=#0000ff>class</font> Factory : <font color=#0000ff>public</font> ShapeFactory {
<font color=#0000ff>public</font>:
Shape* create() { <font color=#0000ff>return</font> <font color=#0000ff>new</font> Square; }
<font color=#0000ff>friend</font> <font color=#0000ff>class</font> ShapeFactoryInitializer;
};
};
<font color=#009900>// Singleton to initialize the ShapeFactory:</font>
<font color=#0000ff>class</font> ShapeFactoryInitializer {
<font color=#0000ff>static</font> ShapeFactoryInitializer si;
ShapeFactoryInitializer() {
ShapeFactory::factories[<font color=#004488>"Circle"</font>] =
<font color=#0000ff>new</font> Circle::Factory;
ShapeFactory::factories[<font color=#004488>"Square"</font>] =
<font color=#0000ff>new</font> Square::Factory;
}
};
<font color=#009900>// Static member definition:</font>
ShapeFactoryInitializer
ShapeFactoryInitializer::si;
<font color=#0000ff>char</font>* shlist[] = { <font color=#004488>"Circle"</font>, <font color=#004488>"Square"</font>, <font color=#004488>"Square"</font>,
<font color=#004488>"Circle"</font>, <font color=#004488>"Circle"</font>, <font color=#004488>"Circle"</font>, <font color=#004488>"Square"</font>, <font color=#004488>""</font> };
<font color=#0000ff>int</font> main() {
vector<Shape*> shapes;
<font color=#0000ff>try</font> {
<font color=#0000ff>for</font>(<font color=#0000ff>char</font>** cp = shlist; **cp; cp++)
shapes.push_back(
ShapeFactory::createShape(*cp));
} <font color=#0000ff>catch</font>(ShapeFactory::BadShapeCreation e) {
cout << e.what() << endl;
<font color=#0000ff>return</font> 1;
}
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < shapes.size(); i++) {
shapes[i]->draw();
shapes[i]->erase();
}
purge(shapes);
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Now the factory method appears in its own
class, <B>ShapeFactory</B>, as the <B>virtual create( )</B>. This is a
<B>private</B> member function, which means it cannot be called directly but can
be overridden. The subclasses of <B>Shape</B> must each create their own
subclasses of <B>ShapeFactory</B> and override the <B>create( )</B> method
to create an object of their own type. These factories are private, so that they
are only accessible from the main factory method. This way, all client
programmers are forced to go through the factory method in order to create
objects.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The actual creation of shapes is
performed by calling <B>ShapeFactory::createShape( )</B>, which is a static
method that uses the <B>map</B> in <B>ShapeFactory</B> to find the appropriate
factory object based on an identifier that you pass it. The factory is
immediately used to create the shape object, but you could imagine a more
complex problem where the appropriate factory object is returned and then used
by the caller to create an object in a more sophisticated way. However, it seems
that much of the time you don’t need the intricacies of the polymorphic
factory method, and a single static method in the base class (as shown in
<B>ShapeFactory1.cpp</B>) will work fine.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Notice that the <B>ShapeFactory</B> must
be initialized by loading its <B>map</B> with factory objects, which takes place
in the singleton <B>ShapeFactoryInitializer</B>. So to add a new type to this
design you must inherit the type, create a factory, and modify
<B>ShapeFactoryInitializer</B> so that an instance of your factory is inserted
in the map. This extra complexity again suggests the use of a <B>static</B>
factory method if you don’t need to create individual factory
objects.</FONT><A NAME="_Toc305593322"></A><A NAME="_Toc305628794"></A><A NAME="_Toc312374165"></A><A NAME="_Toc519042125"></A><BR></P></DIV>
<A NAME="Heading335"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Abstract factories</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <I>Abstract Factory</I> pattern looks
like the factory objects we’ve seen previously, with not one but several
factory methods. Each of the factory methods creates a different kind of object.
The idea is that at the point of creation of the factory object, you decide how
all the objects created by that factory will be used. The example given in
<I>Design Patterns</I> implements portability across various graphical user
interfaces (GUIs): you create a factory object appropriate to the GUI that
you’re working with, and from then on when you ask it for a menu, button,
slider, etc. it will automatically create the appropriate version of that item
for the GUI. Thus you’re able to isolate, in one place, the effect of
changing from one GUI to another.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">As another example suppose you are
creating a general-purpose gaming environment and you want to be able to support
different types of games. Here’s how it might look using an abstract
factory:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C11:AbstractFactory.cpp</font>
<font color=#009900>// A gaming environment</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
#include <iostream>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#0000ff>class</font> Obstacle {
<font color=#0000ff>public</font>:
<font color=#0000ff>virtual</font> <font color=#0000ff>void</font> action() = 0;
};
<font color=#0000ff>class</font> Player {
<font color=#0000ff>public</font>:
<font color=#0000ff>virtual</font> <font color=#0000ff>void</font> interactWith(Obstacle*) = 0;
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -