Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2095667
  • 博文数量: 909
  • 博客积分: 4000
  • 博客等级: 上校
  • 技术积分: 12260
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-06 20:50
文章分类

全部博文(909)

文章存档

2008年(909)

我的朋友

分类:

2008-05-06 21:48:44

一起学习
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); }

};
下载本文示例代码


Pattern Tips 之三Pattern Tips 之三Pattern Tips 之三Pattern Tips 之三Pattern Tips 之三Pattern Tips 之三Pattern Tips 之三Pattern Tips 之三Pattern Tips 之三Pattern Tips 之三Pattern Tips 之三Pattern Tips 之三
阅读(283) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~