Pattern Tips 之三

王朝vc·作者佚名  2006-01-17
窄屏简体版  字體: |||超大  

Pattern Tips 之三

作者:温昱

感谢:《设计模式》一书的作者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种实现):

可以看到,Abstract Factory模式常要使用Factroy Method模式或者Prototype模式,Template Method经常调用Factroy

Method,

●Tip 2:Abstract Factory模式使用Factroy Method模式之例──使用Abstract Factory的MazeGame。注意MazeFactory已内置缺省实现故不是AbstractMazeFactory;还要注意哪里是“对接口编程”,哪里是“对子类名硬编码”。

/////////////////////////////////////////////////////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); }

};

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
 
© 2005- 王朝網路 版權所有 導航