2008年(909)
分类:
2008-05-06 21:48:44
感谢:《设计模式》一书的作者Gamma,Helm,Johnson和Vilssides,译者李英军等
----------------------------------说明----------------------------
Abstract Factory,Factory Method,Prototype。它们都是Creationall Patterns,它们的关系如下图所示:
----------------------------------Abstract Factory----------------------------
●Tip 1:关键字。Family。
●Tip 2:图。书中的原图如下,
我又画了一张,主要是为我后边讨论本模式“支持变化”做准备,
可以看到,Client用了一个Factory,一个Factory可以“生产”一个Product Family(就是多个Product或A Set
of Products),Client使用这一个Product Family。
●Tip 3:实现和使用。
从图中可以看到,ConcreteFactory负责实例化ConcreteProduct,但谁来实例化ConcreteFactory呢?图中Client Class仅对AbstractFactory有关联,但是一个Client Class是不能拥有一个Interface的实例的,而只能拥有它的指针或引用(来支持多态);那么Client Class能new AbstractFactory吗,不仅不能,而且要new ConcreteFactory才对呀。
结论,当“Architect或Achitecture工程师”“实现”Abstract Factory模式时,ConcreteProduct的实例化问题已经考虑在内了,因为这恰恰就是该模式的使命。而当“Application工程师”“使用”Abstract Factory模式时,应负责实例化ConcreteFactory。
在ET 中,Abstract Factory模式实现得非常巧妙。具体实例化哪个ConcreteFactory是“Architect或Achitecture工程师”写在Framework中的一些If语句决定的,这些If语句去读环境变量,解除了“Application工程师”去实例化ConcreteFactory的职责。ET 中的WindowSystem的相关研究,请参考本站(lcspace.nease.net)的Framework栏目。
在MFC中,CDocTemplate也是Abstract Factory模式,并且也非常巧妙地用CRumtimeClass机构解决具体实例化哪个ConcreteFactory的问题。
●Tip 4:支持变化。It makes exchanging product families easy。
不同Product Family一般用于支持类似“多种平台”这样的情形(所以Client一般不同时使用多个Product Family)。想像“Application工程师”欲将Client移植到新平台,由于Client Class对AbstractProduct和AbstractFactory是“良性依赖”(在图中用绿色标出),所以不会引起Client Class的代码变动。如果Client Class还负责“实例化ConcreteProduct”,那么只需改区区2处,比如从
#include "BombedMazeFacory.h" BombedMazeFacory factory; game.CreateMaze( factory );改变成
#include "AnotherMazeFacory.h" //changed AnotherMazeFacory factory; //changed game.CreateMaze( factory );增加新的Product Family,对“Architect或Achitecture工程师”来说,只需新写图中黄色Class:新写了一个New ConcreteFactory以及它生产的New Product Family。
在MFC中,CFrame/CDocument/CView就是一个Product Family,我们的确很容易地创建New Product Fameliy:CMyFrame/CMyDoc/CMyView。
●Tip 5:局限性。Supporting new kinds of products is difficult。
简单说,就是将“支持这6个Product”换成“支持那6个Product”容易,换成“支持那7个Product”难。因为AbstractFactory的操作的个数和Product
Family中Product的个数相对应,它限制了所有ConcreteFactory的接口,这个接口不应也不易随便改。在图中表现得很充份,Client可以有多个,AbstractProduct可以有多个,Product
Family可以有多个,ConcreteFactory可以有多个,唯独AbstractFactory只有一个。
在MFC中,CFrame/CDocument/CView就是一个Product Family,你想在Doc/View arch下创建一个4员组,难。
----------------------------------Factory Method----------------------------
●Tip 1:关键字。Subclass,Virtual,Override。
●Tip 2:图。
●Tip 3:实现和使用。
A factory method define an interface for creating an object,它只要求该Method的责任是Factory:你可以将它实现成纯虚函数/空函数/做相关创建的函数,用于不同情况。但是,在C 中它总是虚函数。
在MFC中,CWnd::Create()就是典型的例子。
●Tip 4:支持变化。
可以看到,2个基类Superclass和AbstractProduct是Framework的组成部份,并且Superclass对AbstractProduct是“对接口编程”,所以是“良性依赖”(在图中用绿色标出),不易引起Superclass的代码变动。
图中黄色的类是New Application新加的,Subclass2对Product2是“恶性依赖”(在图中用红色标出),但又有什么关系呢?因为它们都属于Application,而且Subclass2::FactoryMethod()仅仅创建Product2,涉及的代码很少。
●Tip 5:支持框架。Factory methods pervade toolkits and frameworks。The framework must instantiate classes, but it only knows about abstract classes, which it cannot instantiate。Factory methods eliminate the need to bind application-specific classes into your code。A factory method define an interface for creating an object, but let subclasses CAN (may not) decide which class to instantiate。
----------------------------------Prototype----------------------------
●Tip 1:关键字。Copy,Clone itself。
●Tip 2:图。
●Tip 3:实现和使用。
Wall * BombedWall::Clone() const { return new BombedWall( *this ); }在MFC中,CWnd::Create()就是典型的例子。
●Tip 4:优点。
仅有 1 个“类层次”,而不是象Factory Method一样平行的 2 个。
------------------Abstract Factory,Factory Method,Prototype,Template Method-----------------
●Tip 1:下面是2种典型的应用情况(其中使用Abstract Factory的情况又分2种实现):
/////////////////////////////////////////////////////AbstractFactory #include "Maze.h" #include "Room.h" #include "Wall.h" class MazeFactory //a superclass as a AbstractFactory, but not containing pure virtual method { public: MazeFactory(); //con virtual Maze* MakeMaze() //a factory method, which must be virtual {return new Maze;} virtual Room * MakeRoom(int n) //a factory method, which must be virtual {return new Room(n);} virtrul Wall * MakeWall() //a factory method, which must be virtual {return new Wall;} };
/////////////////////////////////////////////////////Client #include "BombedMazeFacory.h" //这里是对子类名硬编码(类名和文件名一样) void MazeGame::XXXXXXXX ( void ) { BombedMazeFacory factory; //实例化ConcreteFactory,这里是对子类名硬编码 CreateMaze( factory ); } Maze* MazeGame::CreateMaze (MazeFactory & factory) //BombedMazeFacory.h must // have included MazeFactory.h, so MazeFactory is available { // //these 4 statements call Factory to create some Products //这里是对接口编程 // Maze* aMaze = factory.MakeMaze(); Room* r1 = factory.MakeRoom(1); Room* r2 = factory.MakeRoom(2); Door* aDoor = factory.MakeDoor(r1, r2); // //all the rest statements use these Products //这里是对接口编程 // aMaze->AddRoom(r1); aMaze->AddRoom(r2); r1->SetSide(North, factory.MakeWall()); r1->SetSide(East, aDoor); r1->SetSide(South, factory.MakeWall()); r1->SetSide(West, factory.MakeWall()); r2->SetSide(North, factory.MakeWall()); r2->SetSide(East, factory.MakeWall()); r2->SetSide(South, factory.MakeWall()); r2->SetSide(West, aDoor); return aMaze; }
/////////////////////////////////////////////////////ConcreteFactory #include "MazeFactory.h" #include "BombedMaze.h" class BombedMazeFactory : public MazeFactory //a subclass as a ConcreteFactory { public: BombedMazeFactory(); virtual Maze* MakeMaze() //override a factory method, which must be virtual {return new BombedMaze;} };●Tip 3:Template Method经常调用Factroy Method之例──使用Template Method的MazeGame。注意与使用Abstract Factory的MazeGame比较。
/////////////////////////////////////////////////////Superclass class MazeGame { public: MazeGame(); //con Maze* CreateMaze(); //a Template Method virtual Maze* MakeMaze();//4 factory methods, which must be virtual virtual Room* MakeRoom(int n); virtual Wall* MakeWall() const virtual Door* MakeDoor(Room* r1, Room* r2); };
/////////////////////////////////////////////////////Template Method Maze* MazeGame::CreateMaze () { // //本模板方法调用工厂方法MakeXxx() // Maze* aMaze = MakeMaze(); Room* r1 = MakeRoom(1); Room* r2 = MakeRoom(2); Door* theDoor = MakeDoor(r1, r2); aMaze->AddRoom(r1); aMaze->AddRoom(r2); r1->SetSide(North, MakeWall()); r1->SetSide(East, theDoor); r1->SetSide(South, MakeWall()); r1->SetSide(West, MakeWall()); r2->SetSide(North, MakeWall()); r2->SetSide(East, MakeWall()); r2->SetSide(South, MakeWall()); r2->SetSide(West, theDoor); return aMaze; }
/////////////////////////////////////////////////////Subclass #include "MazeGame.h" #include "BombedWall.h" #include "RoomWithABomb.h" class BombedMazeGame : public MazeGame { public: BombedMazeGame(); //con virtual Wall* MakeWall() //override a factory method, which must be virtual { return new BombedWall; } virtual Room* MakeRoom(int n) //override a factory method, which must be virtual { return new RoomWithABomb(n); } };下载本文示例代码