📄 sect08.htm
字号:
createShape = staticmethod(createShape)
<font color=#0000ff>class</font> Shape(object): <font color=#0000ff>pass</font>
<font color=#0000ff>class</font> Circle(Shape):
<font color=#0000ff>def</font> draw(self): <font color=#0000ff>print</font> <font color=#004488>"Circle.draw"</font>
<font color=#0000ff>def</font> erase(self): <font color=#0000ff>print</font> <font color=#004488>"Circle.erase"</font>
<font color=#0000ff>class</font> Factory:
<font color=#0000ff>def</font> create(self): <font color=#0000ff>return</font> Circle()
<font color=#0000ff>class</font> Square(Shape):
<font color=#0000ff>def</font> draw(self):
<font color=#0000ff>print</font> <font color=#004488>"Square.draw"</font>
<font color=#0000ff>def</font> erase(self):
<font color=#0000ff>print</font> <font color=#004488>"Square.erase"</font>
<font color=#0000ff>class</font> Factory:
<font color=#0000ff>def</font> create(self): <font color=#0000ff>return</font> Square()
<font color=#0000ff>def</font> shapeNameGen(n):
types = Shape.__subclasses__()
<font color=#0000ff>for</font> i <font color=#0000ff>in</font> range(n):
<font color=#0000ff>yield</font> random.choice(types).__name__
shapes = [ ShapeFactory.createShape(i)
<font color=#0000ff>for</font> i <font color=#0000ff>in</font> shapeNameGen(7)]
<font color=#0000ff>for</font> shape <font color=#0000ff>in</font> shapes:
shape.draw()
shape.erase()
#:~</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>create( )</B> method. The
different types of shapes must each create their own factory with a
<B>create( )</B> method to create an object of their own type. The actual
creation of shapes is performed by calling
<B>ShapeFactory.createShape( )</B>, which is a static method that uses the
dictionary 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.py</B>) will work fine.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_255">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Notice that the <B>ShapeFactory</B> must
be initialized by loading its dictionary with factory objects, which takes place
in the static initialization clause of each of the shape implementations.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_256">Add Comment</A></FONT><A NAME="_Toc455024533"></A><A NAME="_Toc476705904"></A><A NAME="_Toc534420110"></A><BR></P></DIV>
<A NAME="Heading61"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Abstract factories</H2></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.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_257">Add Comment</A></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:
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_258">Add Comment</A></FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>#: c05:Games.py
# An example of the Abstract Factory pattern.
<font color=#0000ff>class</font> Obstacle:
<font color=#0000ff>def</font> action(self): <font color=#0000ff>pass</font>
<font color=#0000ff>class</font> Player:
<font color=#0000ff>def</font> interactWith(self, obstacle): <font color=#0000ff>pass</font>
<font color=#0000ff>class</font> Kitty(Player):
<font color=#0000ff>def</font> interactWith(self, obstacle):
<font color=#0000ff>print</font> <font color=#004488>"Kitty has encountered a"</font>,
obstacle.action()
<font color=#0000ff>class</font> KungFuGuy(Player):
<font color=#0000ff>def</font> interactWith(self, obstacle):
<font color=#0000ff>print</font> <font color=#004488>"KungFuGuy now battles a"</font>,
obstacle.action()
<font color=#0000ff>class</font> Puzzle(Obstacle):
<font color=#0000ff>def</font> action(self):
<font color=#0000ff>print</font> <font color=#004488>"Puzzle"</font>
<font color=#0000ff>class</font> NastyWeapon(Obstacle):
<font color=#0000ff>def</font> action(self):
<font color=#0000ff>print</font> <font color=#004488>"NastyWeapon"</font>
# The Abstract Factory:
<font color=#0000ff>class</font> GameElementFactory:
<font color=#0000ff>def</font> makePlayer(self): <font color=#0000ff>pass</font>
<font color=#0000ff>def</font> makeObstacle(self): <font color=#0000ff>pass</font>
# Concrete factories:
<font color=#0000ff>class</font> KittiesAndPuzzles(GameElementFactory):
<font color=#0000ff>def</font> makePlayer(self): <font color=#0000ff>return</font> Kitty()
<font color=#0000ff>def</font> makeObstacle(self): <font color=#0000ff>return</font> Puzzle()
<font color=#0000ff>class</font> KillAndDismember(GameElementFactory):
<font color=#0000ff>def</font> makePlayer(self): <font color=#0000ff>return</font> KungFuGuy()
<font color=#0000ff>def</font> makeObstacle(self): <font color=#0000ff>return</font> NastyWeapon()
<font color=#0000ff>class</font> GameEnvironment:
<font color=#0000ff>def</font> __init__(self, factory):
self.factory = factory
self.p = factory.makePlayer()
self.ob = factory.makeObstacle()
<font color=#0000ff>def</font> play(self):
self.p.interactWith(self.ob)
g1 = GameEnvironment(KittiesAndPuzzles())
g2 = GameEnvironment(KillAndDismember())
g1.play()
g2.play()
#:~</PRE></FONT></BLOCKQUOTE><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In this environment,
<B>Player</B> objects interact with <B>Obstacle</B> objects, but there are
different types of players and obstacles depending on what kind of game
you’re playing. You determine the kind of game by choosing a particular
<B>GameElementFactory</B>, and then the <B>GameEnvironment</B> controls the
setup and play of the game. In this example, the setup and play is very simple,
but those activities (the <I>initial conditions</I> and the <I>state change</I>)
can determine much of the game’s outcome. Here, <B>GameEnvironment</B> is
not designed to be inherited, although it could very possibly make sense to do
that.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_259">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This also contains examples of <I>Double
Dispatching</I> and the <I>Factory Method</I>, both of which will be explained
later.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_260">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Of course, the above scaffolding of
<B>Obstacle</B>, <B>Player</B> and <B>GameElementFactory</B> (which was
translated from the Java version of this example) is unnecessary –
it’s only required for languages that have static type checking. As long
as the concrete Python classes follow the form of the required classes, we
don’t need any base classes:
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_261">Add Comment</A></FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>#: c05:Games2.py
# Simplified Abstract Factory.
<font color=#0000ff>class</font> Kitty:
<font color=#0000ff>def</font> interactWith(self, obstacle):
<font color=#0000ff>print</font> <font color=#004488>"Kitty has encountered a"</font>,
obstacle.action()
<font color=#0000ff>class</font> KungFuGuy:
<font color=#0000ff>def</font> interactWith(self, obstacle):
<font color=#0000ff>print</font> <font color=#004488>"KungFuGuy now battles a"</font>,
obstacle.action()
<font color=#0000ff>class</font> Puzzle:
<font color=#0000ff>def</font> action(self): <font color=#0000ff>print</font> <font color=#004488>"Puzzle"</font>
<font color=#0000ff>class</font> NastyWeapon:
<font color=#0000ff>def</font> action(self): <font color=#0000ff>print</font> <font color=#004488>"NastyWeapon"</font>
# Concrete factories:
<font color=#0000ff>class</font> KittiesAndPuzzles:
<font color=#0000ff>def</font> makePlayer(self): <font color=#0000ff>return</font> Kitty()
<font color=#0000ff>def</font> makeObstacle(self): <font color=#0000ff>return</font> Puzzle()
<font color=#0000ff>class</font> KillAndDismember:
<font color=#0000ff>def</font> makePlayer(self): <font color=#0000ff>return</font> KungFuGuy()
<font color=#0000ff>def</font> makeObstacle(self): <font color=#0000ff>return</font> NastyWeapon()
<font color=#0000ff>class</font> GameEnvironment:
<font color=#0000ff>def</font> __init__(self, factory):
self.factory = factory
self.p = factory.makePlayer()
self.ob = factory.makeObstacle()
<font color=#0000ff>def</font> play(self):
self.p.interactWith(self.ob)
g1 = GameEnvironment(KittiesAndPuzzles())
g2 = GameEnvironment(KillAndDismember())
g1.play()
g2.play()
#:~</PRE></FONT></BLOCKQUOTE><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Another way to put this is that
all inheritance in Python is implementation inheritance; since Python does its
type-checking at runtime, there’s no need to use interface inheritance so
that you can upcast to the base type.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_262">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You might want to study the two examples
for comparison, however. Does the first one add enough useful information about
the pattern that it’s worth keeping some aspect of it? Perhaps all you
need is “tagging classes” like this:
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_263">Add Comment</A></FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>class</font> Obstacle: <font color=#0000ff>pass</font>
<font color=#0000ff>class</font> Player: <font color=#0000ff>pass</font>
<font color=#0000ff>class</font> GameElementFactory: <font color=#0000ff>pass</font></PRE></FONT></BLOCKQUOTE><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Then
the inheritance serves only to indicate the type of the derived classes.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_264">Add Comment</A></FONT><A NAME="_Toc534420111"></A><BR></P></DIV>
<A NAME="Heading62"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Exercises</H2></FONT>
<OL>
<LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Add a class
<B>Triangle</B> to <B>ShapeFactory1.py</B>
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_265">Add Comment</A></FONT><LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Add
a class <B>Triangle</B> to <B>ShapeFactory2.py</B>
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_266">Add Comment</A></FONT><LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Add
a new type of <B>GameEnvironment</B> called <B>GnomesAndFairies</B> to
<B>GameEnvironment.py</B>
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_267">Add Comment</A></FONT><LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Modify
<B>ShapeFactory2.py</B> so that it uses an <I>Abstract Factory</I> to create
different sets of shapes (for example, one particular type of factory object
creates “thick shapes,” another creates “thin shapes,”
but each factory object can create all the shapes: circles, squares, triangles
etc.).
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_268">Add Comment</A></FONT></OL>
<DIV ALIGN="CENTER">
<FONT FACE="Verdana, Tahoma, Arial, Helvetica, Sans" size = "-1">
[ <a href="Sect07.htm">Previous Chapter</a> ]
[ <a href="javascript:window.location.href = 'Index.htm';">Table of Contents</a> ]
[ <a href="DocIdx.htm">Index</a> ]
[ <a href="Sect09.htm">Next Chapter</a> ]
</FONT>
<BR>
Last Update:12/31/2001</P></DIV>
</BODY>
</HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -