程序设计模式(二)创建型模式
来源:互联网 发布:用户行为分析python 编辑:程序博客网 时间:2024/06/11 19:51
一、一个MAZE的构造过程
Maze的UML diagram如图所示
可以发现MapSite是斜体表示抽象类,有Room, Door, Wall三个子类继承,这三个就是用继承封装了MapSite的多向性。然而一个Maze,就是Room的聚合,所以Maze通过AddRoom方法来添加这些聚合这些Room. 最后通过MazeGame这个类,来构造这个Maze, 也就是帮助Maze这个对象执行它的AddRoom方法,帮Maze传递消息。所以我说, MazeGame就是Maze的创建类。重点看这个MazeGame创建类
class MazeGame { public: Maze* CreateMaze();//本节将要介绍的创建方法 Maze* CreateSimpleMaze(); Maze* CreateMaze(MazeFactory&);//后面讲的AbstractFactory模式 Maze* CreateMaze(MazeBuilder&);//后面讲的Builder模式 Maze* CreateComplexMaze (MazeBuilder& builder); //构建各种不同迷宫的方法入口};
看看CreateMaze()方法如何实现:
Maze* MazeGame::CreateMaze() { Maze* aMaze = new Maze; Room* r1 = new Room(1); Room* r2 = new Room(2); Door *theDoor = new Door(r1, r2); aMaze->AddRoom(r1); aMaze->AddRoom(r2); r1->SetSide(North, new Wall); r1->SetSide(East, theDoor); r1->SetSide(South, new Wall); r1->SetSide(West, new Wall); r2->SetSide(North, new Wall); r2->SetSide(East, new Wall); r2->SetSide(South, new Wall); r2->SetSide(West, theDoor); return aMaze;}
可以看出,这个Maze被create出来的结构是单一的,就只可能是两个房间,如何自由定义房间空间个数和四壁的内容而不重写代码,这个问题后面是不能解决的。同时,the room, the wall, the door的性质,在SetSide里面已经定义死了,如果下面我们需要给这个Maze定义两种风格,第一种风格是room加上魔法room,door加上用魔法才能打开的魔法Maze, 第二种风格room里面可能有炸弹,走到炸弹里面就死了的炸弹Maze, 用非继承的方法,那么我们呢需要重新写两个Room这个类,在EnchantedMaze中要扩展一个EnchantedRoom类,在BombedMaze中要扩展RoomWithABoom类,如下图所示。
一般的思维,是在CreateMaze的时候,输入的对象还是那个Maze, 但需要给Maze添加一个风格属性,同时在CreateMaze()开头就要添加一行语句判断创建的是哪种风格的Maze, 然后分别对不同的Maze.style, 需要改Room* r1 = new Room(1) 为 Room* r1 = new EnchantedRoom(1) 和 Room* r1 = new RoomWithABomb(1) ,这样一下子就增加了很多的代码量,因为case变多了。所以第一个想法就是调整CreateMaze的输入,这样引出了第一种模式AbstractFactory.
二、AbstractFactory
class MazeFactory {public: MazeFactory(); virtual Maze* MakeMaze() const; virtual Wall* MakeWall() const; virtual Room* MakeRoom(int n) const; virtual Door* MakeDoor(Room* r1, Room* r2) const;}; //这个是基础的AbstractFactory,以后不同风格的ConcreteFactory都是继承此。//AbstractFactory提供创建Maze类对象的方法,并且提供创建Wall,Room,Door的方法,然后让CreateMaze()来调用这个Factory中的方法创建MazeMaze* MazeFactory::MakeMaze() const { return new Maze; }Wall* MazeFactory::MakeWall() const { return new Wall; }Room* MazeFactory::MakeRoom(int n) const { return new Room(n); }Door* MazeFactory::MakeDoor(Room* r1, Room* r2) const { return new Door(r1, r2); }下面是实现了BomdedMazeFactory
class BombedMazeFactory : public MazeFactory {public: BombedMazeFactory(); virtual Wall* MakeWall() const; virtual Room* MakeRoom(int n) const;};Wall* BombedMazeFactory::MakeWall () const { return new BombedWall;} Room* BombedMazeFactory::MakeRoom (int n) const { return new RoomWithABomb(n);}注意这里虚函数的重写,没有把Abstract中的所有虚函数都重写,就重写了需要改变的Room 和 Wall同理是EnchantedMazeFactory的实现
class EnchantedMazeFactory : public MazeFactory {public: EnchantedMazeFactory(); virtual Room* MakeRoom(int n) const; virtual Door* MakeDoor(Room* r1, Room* r2) const;protected: Spell* CastSpell() const;};Room* EnchantedMazeFactory::MakeRoom(int n) const { return new EnchantedRoom(n, CastSpell()); }Door* EnchantedMazeFactory::MakeDoor(Room* r1, Room* r2) const { return new DoorNeedingSpell(r1, r2); }把上面这个放到CreateMaze()中就是如下所示,注意我们完全没有必要粉case讨论,直接输入AbstractFactory基类类型就可以,
Maze* MazeGame::CreateMaze (MazeFactory& factory) { Maze* aMaze = factory.MakeMaze(); Room* r1 = factory.MakeRoom(1); Room* r2 = factory.MakeRoom(2); Door* aDoor = factory.MakeDoor(r1, r2); 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;}然后想要创建哪种风格的Maze,就输入相应的ConcreteFactory, 输入进去了就可以形成多态,CreateMaze()里面的代码就一行不用改了。创建代码如下
BombedMazeFactory BFactory;EnchantedMazeFactory EFactory;Maze* pBMaze = MazeGame::CreateMaze(BFactory);Maze* pEMaze = MazeGame::CreateMaze(EFactory);所以,现在就知道了如何利用AbstractFactory来通过AbstractFactory派生到ConcreteFactroy的过程,就在这些类里面封装了我们所需要的变化,因此在CreateMaze里面就可以用单一的代码动态的展现我们的多种风格Maze的生成,这就是模式的精华。
2.Builder模式
class MazeBuilder {public: virtual void BuildMaze() { } virtual void BuildRoom(int room) { } virtual void BuildDoor(int roomFrom, int roomTo) { } virtual Maze* GetMaze() { return 0; }protected: MazeBuilder();};MazeGame中CreateMaze()方法重新定义如下
Maze* MazeGame::CreateMaze (MazeBuilder& builder) { builder.BuildMaze(); builder.BuildRoom(1); builder.BuildRoom(2); builder.BuildDoor(1, 2); return builder.GetMaze();}对比与AbstractFactory模式,可以发现CreateMaze中所有的对Maze制造过程都只依赖builder对象,不需要对Maze对象直接操作,而是把对Maze对象的操作放到了Builder里面的方法中完成。当我们具体定义一个Builder的时候,通常要把基类的Builder继承,如派生一个StandardMazeBuilder
class StandardMazeBuilder : public MazeBuilder {public: StandardMazeBuilder(); virtual void BuildMaze(); virtual void BuildRoom(int); virtual void BuildDoor(int, int); virtual Maze* GetMaze();private: Direction CommonWall(Room*, Room*); Maze* _currentMaze;};下面看建造Maze的方法,本来是要调用Maze对象来完成,但是现在是被封装到了Builder对象中了
StandardMazeBuilder::StandardMazeBuilder () { _currentMaze = 0;}void StandardMazeBuilder::BuildMaze () { _currentMaze = new Maze;}Maze *StandardMazeBuilder::GetMaze () { Maze* maze = _currentMaze; return maze;}void StandardMazeBuilder::BuildRoom (int n) { if (!_currentMaze->RoomNo(n)) { Room* room = new Room(n); _currentMaze->AddRoom(room); room->SetSide(North, new Wall); room->SetSide(South, new Wall); room->SetSide(East, new Wall); room->SetSide(West, new Wall); }}void StandardMazeBuilder::BuildDoor (int n1, int n2) { Room* r1 = _currentMaze->RoomNo(n1); Room* r2 = _currentMaze->RoomNo(n2); Door* d = new Door(r1, r2); r1->SetSide(CommonWall(r1,r2), d); r2->SetSide(CommonWall(r2,r1), d);}这样一来,在CreateMaze()方法中代码就更简单了,这样完全将Maze的构建和Maze对象可以隔离开来,单纯用builder对象就可以完成了。同理,对于不同风格的Maze的创建,需要继承不同种类的Builder. 而且,builder的基类也不是抽象类,因为里面如果有纯虚函数一定要被实现,而实际中builder的派生出来的conceate builder中差别比较大,不一定每个都会用到基类中的纯虚函数, 所以就没必要采用抽象类来作为基类。
void Test1() {Maze* maze;MazeGame game;StandardMazeBuilder builder;game.CreateMaze(builder);maze = builder.GetMaze();}
- 程序设计模式(二)创建型模式
- 软件设计模式-创建型模式(二)
- 设计模式(二) 创建型模式
- (二)创建型模式--工厂模式
- 创建型模式(二)
- 设计模式中创建型模式 (二):原型模式
- 《JS高级程序设计》第6章读书笔记:创建对象(二)原型模式和组合模式
- (二)设计模式之创建型
- JAVA设计模式(二)-创建型
- 设计模式(二)单例模式(创建型)
- 设计模式详细系列教程 (二) 创建型模式
- (创建型模式二)工厂方法模式
- 设计模式(二)工厂方法模式(FactoryMethod)-创建型
- 创建型:设计模式之抽象工厂模式(二)
- Java_23种设计模式(二)----- 创建型模式
- 二:创建型模式:抽象工厂模式
- 设计模式-创建型软件设计模式(二)
- 程序设计模式(二) C++抽象工厂(Abstract Factory)模式
- 输入一个奇数n,打印出一个n*n的矩阵,每个数字是从1到n*n的整数,要使每一行,每一列的数字之和都相等
- 系统并行化设计的一次思考
- 【Objective-C Runtime】类和对象的数据结构和消息传递机制
- 记一次SSH中文乱码解决方案
- 51Nod-算法马拉松23-B-谷歌的恐龙(数学期望)
- 程序设计模式(二)创建型模式
- SSH框架搭建电商系统之密码找回
- Java的synchronized关键字:同步机制总结
- 总结
- VirtualBox fedora系统安装增强工具
- 求数组的连续子数组之和的最大值(一维二维)
- 人口模型回归
- 生命之树
- ploymer (一) 第一个demo