为方便读者,本文已添加至索引:
在笔记Builder模式中,我们曾见到了最初用于创建平行世界的函数createWorld,并且它是Mage类的成员函数(毕竟是专属于魔导士的强大咒语嘛)。然而在上篇笔记Singleton模式中,时の魔导士组建了一个极为强大的WorldMgr议会来代替他维持世界。“如果他们甚至连改造地形的能力都没有的话,会让人很苦恼呢……”魔导士心想,“或许我可以给他们提供一套地图编辑器……或者说世界改造器,就像暴雪那帮家伙的星际争霸。”对于如何设计一套通用的世界改造器,时の魔导士打算引入Prototype模式。它能极大地减少系统中类的数目,同时也更易于在其中添加新的环境因素。
目的分类
范围准则
主要功能
适用情况
参与部分
协作过程
UML图
首先,我们提供WorldPrototypeEditor类,它将使用要创建的对象的原型来初始化,这样我们就不需要仅仅为了改变它所创建的地形的类而再生成子类了:
class WorldPrototypeEditor {
public:
WorldPrototypeEditor(Mountain*, Ocean*, Plant*);
virtual Mountain\* makeMountain();
virtual Ocean\* makeOcean();
virtual Plant\* makePlant(Mountain\*);
private:
Mountain* _prototypeMountain;
Ocean* _prototypeOcean;
Plant* _prototypePlant;
}
由于是内部测试版,我们仅仅考虑最简单的地形改造器啦,能造山,造水,然后在山上种些小树苗什么的就完事了。它的的构造器只初始化它的原型:
WorldPrototypeEditor::WorldPrototypeEditor(Mountain* m, Ocean* o, Plant* p)
{
_prototypeMountain = m;
_prototypeOcean = o;
_prototypePlant = p;
}
用于创建山、海洋和树的成员函数是相似的:每个都要克隆一个原型,然后初始化。让我们来看看makeMountain和makeTree的定义:
Mountain* WorldPrototypeEditor::makeMountain()
{
return _prototypeMountain->clone();
}
Plant* WorldPrototypeEditor::makePlant(Mountain* m)
{
Plant* p = _prototypePlant->clone();
p->addTo(m);
return p;
}
因此,当泰坦们开始着手编辑世界地形的时候,只需使用基本地形构件的原型进行初始化,就可以由WorldPrototypeEditor来创建一个原型的或缺省的世界:
WorldPrototypeEditor simpleWorldEditor;
World* world = WorldMgr::getInstance()->editWorld(simpleWorldEditor);
一个可以被用作原型的对象,例如Plant的实例,必须支持clone操作。它还必须有一个拷贝构造器用于克隆。它可能还需要一个独立的操作来重新初始化内部的状态:
class Plant {
public:
Plant();
Plant(const Plant&);
virtual void initialize(Category\*);
virtual Plant\* clone() const;
private:
Category* _cg;
}
Plant::Plant(const Plant& other) {
_cg = other._cg;
}
void Plant::initialize(Category* c)
{
_cg = c;
}
Plant* Plant::clone() const {
return new Plant(*this);
}
例子中私有成员变量_cg仅仅是决定了植物的种类,但是如果我们想为这个编辑器添加一些扩展包。比如说,增加一些特别的植物:苹果树怎么样?AppleTree必须重定义clone,并且实现相应的构造器。
class AppleTree : public Plant {
public:
AppleTree();
AppleTree(const AppleTree&);
virtual Plant\* clone() const;
int hasApple();
private:
int _apple;
}
AppleTree::AppleTree(const AppleTree& other) : Plant(other) {
_apple = other._apple;
}
Plant* AppleTree::clone() const {
return new AppleTree(*this);
}
在这个情况下,我们可以用带苹果树扩展包的原型集合来初始化WorldPrototypeEditor,见下面的调用:
WorldPrototypeEditor appleWorldEditor(new Mountain(), new Ocean(), new AppleTree());
我们可以看一个简单的UML图来更加直观地感受:
Prototype模式有许多和Abstract Factory、Builder模式一样的效果:它对客户隐藏了具体的产品类,因此减少了客户需要知道的名字的数目。此外,这些模式使客户无需改变即可使用与特定应用相关的类。当然Prototype模式还有它独到的一面:
对于有些语言,例如JavaScript,它就提供了一个等价于原型的东西(对象),原型模式几乎是它所固有的特性,无处不在。
今天的笔记就到这里了,欢迎大家批评指正!如果觉得可以的话,好文推荐一下,我会非常感谢的!
手机扫一扫
移动阅读更方便
你可能感兴趣的文章