写在前面
为方便读者,本文已添加至索引:
设计模式
学习笔记索引
在笔记Builder模式中,我们曾见到了最初用于创建平行世界的函数createWorld,并且它是Mage类的成员函数(毕竟是专属于魔导士的强大咒语嘛)。然而在上篇笔记Singleton模式中,时の魔导士组建了一个极为强大的WorldMgr议会来代替他维持世界。“如果他们甚至连改造地形的能力都没有的话,会让人很苦恼呢……”魔导士心想,“或许我可以给他们提供一套地图编辑器……或者说世界改造器,就像暴雪那帮家伙的星际争霸。”对于如何设计一套通用的世界改造器,时の魔导士打算引入Prototype模式。它能极大地减少系统中类的数目,同时也更易于在其中添加新的环境因素。
要点梳理
-
目的分类
- 对象创建型模式
-
范围准则
- 对象(该模式处理对象间的关系,这些关系在运行时刻是可以变化的,更具动态性)
-
主要功能
- 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
-
适用情况
- 当一个系统应该独立于它的产品创建、构成和表示时
- 当要实例化的类是在运行时刻指定时,例如,通过动态装载
- 为了避免创建一个与产品类层次平行的工厂类层次时
- 当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。
-
参与部分
- Prototype:声明一个克隆自身的接口
- ConcretePrototype:实现一个克隆自身的操作
- Client:让一个原型克隆自身从而创建一个新的对象
-
协作过程
- 客户请求一个原型克隆自身
- 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模式还有它独到的一面:
- 运行时刻增加和删除产品。Prototype允许只通过客户注册原型实例就可以将一个新的具体产品类并入系统。它比其他创建型模式更为灵活,因为客户可以在运行时刻建立和删除原型。
- 改变值以指定新对象。高度动态的系统允许我们通过对象复合定义新的行为。例如,通过为一个对象变量指定值,并且不定义新的类。我们通过实例化已有类并且将这些实例注册为客户对象的原型,就可以有效定义新类别的对象。客户可以将职责代理给原型,从而表现出新的行为。
- 改变结构以指定新对象。许多应用由部件和子部件来创建对象。例如电路设计编辑器就是由子电路来构造电路的。为方便起见,这样的应用通常允许我们实例化复杂的、用户定义的结构,比方说,一次又一次的重复使用一个特定的子电路。对于Prototype模式,我们仅需将这个子电路作为一个原型增加到可用的电路元素选择板中。
- 减少子类的构造。Factory Method经常产生一个与产品类层次平行的Creator类层次。Prototype模式使得我们克隆一个原型而不是请求一个工厂方法去产生一个新的对象,因此我们根本不需要Creator类层次。这一优点主要适用于像C++这样不将类作为一级类对象的语言。
- 用类动态配置。应用一些运行时刻环境允许我们动态将类装载到应用中。
对于有些语言,例如JavaScript,它就提供了一个等价于原型的东西(对象),原型模式几乎是它所固有的特性,无处不在。
写在最后
今天的笔记就到这里了,欢迎大家批评指正!如果觉得可以的话,好文推荐一下,我会非常感谢的!
[学习笔记]设计模式之Prototype的更多相关文章
-
Java程序猿的JavaScript学习笔记(5——prototype和Object内置方法)
计划按例如以下顺序完毕这篇笔记: Java程序猿的JavaScript学习笔记(1--理念) Java程序猿的JavaScript学习笔记(2--属性复制和继承) Java程序猿的JavaScript ...
-
[学习笔记]设计模式之Abstract Factory
写在前面 为方便读者,本文已添加至索引: 设计模式 学习笔记索引 在上篇笔记Builder设计模式中,时の魔导士祭出了自己的WorldCreator.尽管它因此能创造出一个有山有树有房子的世界,但是白 ...
-
[学习笔记]设计模式之Builder
写在前面 为方便读者,本文已添加至索引: 设计模式 学习笔记索引 作为一个新入职的魔导士呢,哦不,是程序员,我以为并没有太多机会去设计项目的软件架构.但是,工作一段时间之后,自己渐渐意识到,哪怕是自己 ...
-
[学习笔记]设计模式之Adapter
写在前面 为方便读者,本文已添加至索引: 设计模式 学习笔记索引 Adapter(适配器)模式主要解决接口不匹配的问题.为此,让我们要回到最初Builder模式创建平行世界时,白雪公主和小霍比特人的谜 ...
-
[学习笔记]设计模式之Bridge
写在前面 为方便读者,本文已添加至索引: 设计模式 学习笔记索引 “魔镜啊魔镜,谁是这个世界上最美丽的人?”月光中,一个低沉的声音回荡在女王的卧室.“是美丽的白雪公主,她正和小霍比特人们幸福快乐地生活 ...
-
[学习笔记]设计模式之Command
为方便读者,本文已添加至索引: 设计模式 学习笔记索引 写在前面 在上篇Chain of Responsibility(职责链)模式笔记中,我们学习了一种行为型设计模式.今天,我们继续这一主题,来学习 ...
-
[学习笔记]设计模式之Chain of Responsibility
为方便读者,本文已添加至索引: 设计模式 学习笔记索引 写在前面 最近时间比较紧,所以发文的速度相对较慢了.但是看到园子里有很多朋友对设计模式感兴趣,我感觉很高兴,能够和大家一起学习这些知识. 之前的 ...
-
[学习笔记]设计模式之Composite
为方便读者,本文已添加至索引: 设计模式 学习笔记索引 写在前面 在Composite(组合)模式中,用户可以使用多个简单的组件以形成较大的组件,而这些组件还可能进一步组合成更大的.它重要的特性是能够 ...
-
[学习笔记]设计模式之Proxy
为方便读者,本文已添加至索引: 设计模式 学习笔记索引 写在前面 “魔镜啊魔镜,谁是这个世界上最美丽的人?” 每到晚上,女王都会问魔镜相同的问题(见Decorator模式).这是她还曾身为女巫时留下的 ...
随机推荐
-
Powershell 字符串处理案例
有一张Excel表格收集了计算机名和IP地址,另外一张表有计算机名,需要找出这张表中计算机名对应的IP地址. #定义函数Get-LikeContentInfo function Get-LikeCon ...
-
JSP 简介
160901 1. 一句话介绍什么是JSP? 和java相关的技术,可以开发出动态的,高性能的Web应用程序,的一门开发语言 2. 优点即特点,那么jsp的优点有哪些呢? JSP实现的We ...
-
C#与数据库访问技术总结(九)之实例
实例 更新记录 在本例子中,建立一个供用户输入学生学号和姓名的文本框和几个对应不同操作类型的更新信息按钮,当用户输入信息以后单击相应的按钮则执行相应的操作.在此实例中还将接触到服务器信息验证的相关知识 ...
-
简单使用URLConnection、HttpURLConnection和HttpClient访问网络资源
URL的openConnection方法将返回一个URLConnection,该对象表示应用程序和URL之间的通信连接.程序可以通过它的实例向该URL发送请求,读取URL引用的资源. 下面通过一个简单 ...
-
Java线程:条件变量、原子量、线程池等
一.条件变量 条件变量实现了java.util.concurrent.locks.Condition接口,条件变量的实例化就是通过一个Lock对象上调用newCondition()方法获得的,这样条件 ...
-
pig简单的代码实例:报表统计行业中的点击和曝光量
注意:pig中用run或者exec 运行脚本.除了cd和ls,其他命令不用.在本代码中用rm和mv命令做例子,容易出错. 另外,pig只有在store或dump时候才会真正加载数据,否则,只是加载代码 ...
-
shell脚本可以解决的问题
1.各类监控脚本,文件,内存,磁盘,端口 url 监控报警 2.监控网站目录文件是否被篡改,以及如何恢复 3.如何开发各类服务rsync nginx mysql等启动停止脚本 4.开发mysql主从复 ...
-
[CQOI2016]K远点对
嘟嘟嘟 做过[国家集训队]JZPFAR这道题的话,这题就不难了. 我们维护一个长度为\(k\)的小根堆,在加入第\(i\)个点之前,用\([1, i - 1]\)这些点离点\(i\)的距离更新答案.这 ...
-
.Net 学习过程
1.C#面向过程编程. 2.C#面向对象基础. 3.WPF教程. 4.SQL语句. 5.ADO.Net. 6.HTML.JavaScript.Dom. 7.ASP.Net.
-
js怎么样根据select的name取到值
先看一下ASP.NET MVC的html: 在jQuery中,可以写: