1.场景分析
2.意图
用原型实例指定创建对象的类型,并且通过拷贝这些原型创建新的对象。
3.适用性
- 当一个系统应该独立于它的产品创建、构成和表示时。
- 当要实例化的类是在运行时刻指定时,例如动态加载。
- 为了避免创建一个与产品类层次平行的工厂类层次时。
- 当一个类的实例只能有几个不同状态组合中的一种时。
4.结构
5.优缺点
优点:
- 可以在运行时刻增加和删除产品。
- 可以通过改变值来指定新对象。高度动态的系统允许你通过对象复合定义新的行为,而不用定义新的类型。实际上,克隆一个原型类似于实例化了一个类,Prototype模式可以极大的减少系统所需要的类的数目。
- 用类动态配置应用。一个希望动态载入类的实例的应用不能静态引用类的构造器。而应该由运行环境在载入时自动创建每个类的实例,并用原型管理器来管理这个实例。
缺点:
Prototype的主要缺点是每一个原型都必须实现clone操作,也有时是很困难的。当内部包括一些不支持拷贝或者有循环引用的对象时,实现克隆操作将很困难。
6.实现
1>使用一个原型管理器。当一个系统中原型数目不固定时(也就是它们可以被动态创建或销毁),要保持一个可用原型的注册表。原型管理器是一个关联存储器,它返回一个与给定关键字相匹配的原型。
2>实现克隆操作。Prototype的最困难处就在于正确的实现clone操作,当对象包含循环引用时尤为棘手。克隆一个结构复杂的原型通常需要深拷贝,因此你必须保证克隆对象的构建也是原型构件的克隆(特别是对于一些指针和引用)。
3>初始化克隆对象。通常你需要引入一个Init操作来设定克隆后对象的状态。
7.代码示例
我们接下来用原型模式来实现迷宫游戏。
#include <iostream>
using namespace std;
class Room;
class Maze
{
public:
Maze *clone();
void addRoom(Room *room);
//...
};
class Room
{
public:
Room *clone();
//...
};
class Wall
{
public:
Wall *clone();
//...
};
class Door
{
public:
Door(){}
Door(const Door &door)
{
_r1 = door._r1;
_r2 = door._r2;
}
void init(Room *r1, Room *r2)
{
_r1 = r1;
_r2 = r2;
}
Door*clone()
{
return new Door(*this);
}
private:
Room *_r1 = nullptr;
Room *_r2 = nullptr;
};
//抽象工厂
class MazeFactory
{
public:
virtual Maze *makeMaze();
virtual Room *makeRoom(int roomId);
virtual Wall *makeWall();
virtual Door *makeDoor(Room *r1, Room *r2);
};
//迷宫游戏类
class MazeGame
{
public:
//通过一个MazeBuilder来创建一个迷宫
Maze *createMaze(MazeFactory *factory)
{
Maze *maze = factory->makeMaze();
Room *r1 = factory->makeRoom(1);
Room *r2 = factory->makeRoom(2);
Door *door = factory->makeDoor(r1, r2);
maze->addRoom(r1);
maze->addRoom(r2);
return maze;
}
};
class MazePrototypeFactory : public MazeFactory
{
public:
MazePrototypeFactory(Maze *m, Wall *w, Room *r, Door *d)
{
_mazeProto = m;
_wallProto = w;
_roomProto = r;
_doorProto = d;
}
Maze *makeMaze()
{
return _mazeProto->clone();
}
Room *makeRoom()
{
return _roomProto->clone();
}
Wall *makeWall()
{
return _wallProto->clone();
}
Door *makeDoor(Room *r1, Room *r2)
{
Door *door = _doorProto->clone();
door->init(r1, r2);
return door;
}
private:
Maze *_mazeProto = nullptr;
Room *_roomProto = nullptr;
Wall *_wallProto = nullptr;
Door *_doorProto = nullptr;
};
int main()
{
MazeGame game;
MazePrototypeFactory mazeFactory(new Maze(), new Wall(), new Room(), new Door());
Maze *maze = game.createMaze(&mazeFactory);
}