UML软件工程组织

Pattern Tips 之三
作者:温昱(选自松耦合空间)


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); }
};
                                   上一页      下一页
 
 

版权所有:UML软件工程组织