3-创建型模式

创建型模式

创建型设计模式抽象了实例化过程。它们帮助一个系统独立于如何创建、组合和表示它的那些对象。

主要特征

  • 第一,它们都将关于该系统使用哪些具体的类的信息封装起来。
  • 第二,它们隐藏了这些类的实例是如何被创建和放在一起的。

常用的对象创建型模式有:

背景

游戏中的功能类

以一个地牢探索游戏创建房间为例,讨论 5 种模式。涉及的主要类有:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 房间的方向,北南东西
enum Direction {N,S,E,W}; 

// 创建迷宫的类
class MazeGame{
public:
	Maze* CreateMaze();
}

// 地图点的抽象类,有Room,Wall,Door3个子类
class MapSite{
public:
	virtual void Enter() = 0; // 进入该地点
}
// 墙
class Wall:public MapSite{
public:
	virtual void Enter();
}
// 门
class Door:public MapSite{  
public:
	Door(Room*=0,Room*=0);
	Room* OtherSideFrom(Room*);
	virtual void Enter();
private:
	Room *_room1,*_room2;
	bool _isOpen;
}
// 房间
class Room:public MapSite{
public:
	Room(int roomNo);
	MapSite *GetSide(Direction) const;
	virtual void Enter();
private:
	MapSite *_sides[4]; // 东西南北的地图点
	int _roomNumber;    // 房间编号
}

各类创建方法比较

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// 硬编码
Maze* MazeGame::CreateMaze(){
	Maze* aMazenew Maze;
	Room* r1 = new Room(1); 
	Room* r2 new Room(2);
	Door* theDoor = new Door(rl, r2);
	
	aMaze->AddRoom (r1);
	aMaze->AddRoom (r2);
	
	r1->SetSide (North, new Wall); rl>SetSideEast.theDoor);
	rl->SetSide (South, new Wall); rl->SetSide (West, new Wall);
	r2->SetSide (North, new Wal1); r2->SetSide (East, new Wall): 
	r2->SetSide(South, new Wall); r2->SetSide (West, theDoor) 
	return aMaze;
}
  • 硬编码方式的主要缺点是不灵活,修改迷宫的布局意味着修改这个实例方法,这容易产生错误也不易于复用
  • Factory Method:CreateMaze 调用虚函数而不是构造器来创建它需要的房间、墙壁和门,那么你可以创建一个 MazeGame 的子类并重定义这些虚函数,从而改变被实例化的类。
  • Abstract Factory:传递一个对象给 CreateMaze 作为参数来创建房间、墙壁和门,那么你可以传递不同的参数来改变房间、墙壁和门的类
  • Builder:传递一个对象给 CreateMaze,这个对象可以在它所建造的迷宫中使用增加房间、墙壁和门的操作来全面创建一个新的迷宫,那么你可以使用继承来改变迷宫的一些部分或迷宫的建造方式。
  • Prototype:CreateMaze 由多种原型的房间、墙壁和门对象参数化,它复制并将这些对象增加到迷宫中,那么你可以用不同的对象替换这些原型对象以改变迷宫的构成。
  • Singleton:可以保证每个游戏中仅有一个迷宫而且所有的游戏对象都可以迅速访问它——不需要求助于全局变 量或函数。Singleton 也使得迷宫易于扩展或替换,且不需要变动已有的代码。

讨论

对系统进行参数化主要有 2 种方法:

  • 生成创建对象的类的子类,这对应于使用 Factory Method:缺点是,仅为了改变产品类,就可能需要创建一个新的子类
  • 定义一个对象负责明确产品对象的类,并将它作为该系统的参数:对应 Abstract Factory(3.1)、Builder(3.2)和 Prototype(3.4)。这三个模式都涉及创建一个新的负责创建产品对象的“工厂对象”
    • Abstract Factory 由这个工厂对象产生多个类的对象
    • Builder 使用一个相对复杂的协议,由这个工厂对象逐步创建一个复杂产品
    • Prototype 由该工厂对象通过拷贝原型对象来创建产品对象

通常,设计以使用 Factory Method 开始,并且当设计者发现需要更大的灵活性时,设计便会向其他创建型模式演化。

  • Abstract Factory、Prototype 或 Builder 的设计通常比使用 Factory Method 的设计更灵活,但它们也更加复杂