原型模式--prototype
什么是原型模式?
在GOF的《设计模式:可复用面向对象软件的基础》中是这样说的:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。这这个定义中,最重要的一个词是“拷贝”,也就是口头上的复制,而这个拷贝,也就是原型模式的精髓所在。
举一个最简单的例子来说明原型模式:记得上小学的时候,老师把需要做的课外习题写到黑板上,而下面的我们都要把这些题抄写到自己的本子上,回家做好,第二天交上来,也就是每道题,全班50个人,每个人都要抄写一遍。按照现在的时间理论来说,就是浪费了50个人的时间。但是,那个时候条件限制,老师也是不得已而为之。现在好了,老师做一份电子版的习题,打印一份,然后拿着这份打印的原版,就可以复制出50份。
结合原型模式的概念进行分析,老师打印出来的那一份,就是“原型”,而复制出来的那50份,就是使用的“拷贝”。而原型模式就是这么简单的一个道理,通过现有的东西,再复制出一个来。
为什么要使用原型模式?
原型模式和建造者模式、工厂方法模式一样,都属于创建型模式的一种。简单的来说,我们使用原型模式,就是为了创建对象。但是,在以下场景下,使用原型模式是最好的选择:
- 当我们的对象类型不是开始就能确定的,而这个类型是在运行期确定的话,那么我们通过这个类型的对象克隆出一个新的对象比较容易一些;
- 有的时候,我们需要一个对象在某个状态下的副本,此时,我们使用原型模式是最好的选择;例如:一个对象,经过一段处理之后,其内部的状态发生了变化;这个时候,我们需要一个这个状态的副本,如果直接new一个新的对象的话,但是它的状态是不对的,此时,可以使用原型模式,将原来的对象拷贝一个出来,这个对象就和之前的对象是完全一致的了;
- 当我们处理一些比较简单的对象时,并且对象之间的区别很小,可能就几个属性不同而已,那么就可以使用原型模式来完成,省去了创建对象时的麻烦了;
- 有的时候,创建对象时,构造函数的参数很多,而自己又不完全的知道每个参数的意义,就可以使用原型模式来创建一个新的对象,不必去理会创建的过程,让创建过程见鬼去吧。
所以,在上述的的情况下,在设计的时候,适当的考虑一下原型模式,减少对应的工作量,减少程序的复杂度,提高效率。
用UML类图表示原型模式

由于克隆需要一个原型,而上面的类图中Prototype就这个原型,Prototype定义了克隆自身的Clone接口,由派生类进行实现,而实现原型模式的重点就在于这个Clone接口的实现。ConcretePrototype1类和ConcretePrototype2类继承自Prototype类,并实现Clone接口,实现克隆自身的操作;同时,在ConcretePrototype1类和ConcretePrototype2类中需要重写默认的复制构造函数,供Clone函数调用,Clone就是通过在内部调用重写的复制构造函数实现的。在后续的编码过程中,如果某个类需要实现Clone功能,就只需要继承Prototype类,然后重写自己的默认复制构造函数就好了。好比在C#中就提供了ICloneable接口,当某个类需要实现原型模式时,只需要实现这个接口的道理是一样的。
代码实现
/*****************************************************
* \file PrototypePatternDemo.cpp
* \date 2016/07/21 21:17
* \author ranjiewen
* \contact: ranjiewen@outlook.com
//原型模式和建造者模式、工厂方法模式一样,都属于创建型模式的一种。简单的来说,我们使用原型模式,就是为了创建对象。
//如果某个类需要实现Clone功能,就只需要继承Prototype类,然后重写自己的默认复制构造函数就好了。
*****************************************************/
#include <iostream>
using namespace std;
//接口
class Prototype
{
public:
Prototype(){}
virtual ~Prototype(){}
;
};
//实现
class ConcretePrototype :public Prototype
{
public:
ConcretePrototype(){}
virtual ~ConcretePrototype(){}
//拷贝构造函数
ConcretePrototype(const ConcretePrototype& rhs)
{
this->m_counter = rhs.m_counter;
}
virtual ConcretePrototype* clone()
{
//调用拷贝构造函数
return new ConcretePrototype(*this);
}
private:
int m_counter;
};
int main()
{
ConcretePrototype* conProA = new ConcretePrototype();
ConcretePrototype* conProB = conProA->clone();
delete conProA;
conProA = nullptr;
delete conProB;
conProB = nullptr;
;
}
上述代码实现了一个最简单的原型模式,但是已经将原型模式的基本实现原理展现出来了。而有的时候,当调用Clone获得了一个复制的对象以后,需要改变对象的状态,此时就可能需要在ConcretePrototype类中添加一个Initialize操作,专门用于初始化克隆对象。由于在Clone的内部调用的是复制构造函数,而此处又涉及到深复制和浅复制的问题。所以,在实际操作的过程中,这些问题,都需要进行仔细的考虑。
与其它创建型模式的比较
工厂方法模式、抽象工厂模式、建造者模式和原型模式都是创建型模式。工厂方法模式适用于生产较复杂,一个工厂生产单一的一种产品的时候;抽象工厂模式适用于一个工厂生产多个相互依赖的产品;建造者模式着重于复杂对象的一步一步创建,组装产品的过程,并在创建的过程中,可以控制每一个简单对象的创建;原型模式则更强调的是从自身复制自己,创建要给和自己一模一样的对象。
总结
原型模式作为创建型模式中最特殊的一个模式,具体的创建过程,是由对象本身提供,这样我们在很多的场景下可以很方便的快速的构建新的对象。但是,原型模式的最大缺点是继承原型的子类都要实现Clone操作,这个是很困难的。例如,当所考虑的类已经存在时就难以新增Clone操作。当内部包括一些不支持拷贝或者有循环引用的对象时,实现克隆可能也会很困难。说以说,每一种设计模式都有它的优点和缺点,在设计的时候,我们需要进行权衡各方面的因素,扬长避短。
原型模式--prototype的更多相关文章
- Net设计模式实例之原型模式( Prototype Pattern)
一.原型模式简介(Brief Introduction) 原型模式(Prototype Pattern):用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象. Specify the kin ...
- 二十四种设计模式:原型模式(Prototype Pattern)
原型模式(Prototype Pattern) 介绍用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象.示例有一个Message实体类,现在要克隆它. MessageModel usin ...
- 设计模式(四)原型模式Prototype(创建型)
设计模式(四)原型模式Prototype(创建型) 1. 概述 我们都知道,创建型模式一般是用来创建一个新的对象,然后我们使用这个对象完成一些对象的操作,我们通过原型模式可以快速的创建一个对象 ...
- 乐在其中设计模式(C#) - 原型模式(Prototype Pattern)
原文:乐在其中设计模式(C#) - 原型模式(Prototype Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 原型模式(Prototype Pattern) 作者:weba ...
- 原型模式-Prototype(Java实现)
原型模式-Prototype 通过复制(克隆.拷贝)一个指定类型的对象来创建更多同类型的对象. 就像去蛋糕店买蛋糕一样. 柜台里的蛋糕都是非卖品. 只是为顾客提供一种参照. 当顾客看上某一个样式的蛋糕 ...
- 原型模式 prototype 创建型 设计模式(七)
原型模式 prototype 意图 用原型实例指定需要创建的对象的类型,然后使用复制这个原型对象的方法创建出更多同类型的对象 显然,原型模式就是给出一个对象,然后克隆一个或者更多个对象 小时候看 ...
- PHP设计模式 原型模式(Prototype)
定义 和工厂模式类似,用来创建对象.但实现机制不同,原型模式是先创建一个对象,采用clone的方式进行新对象的创建. 场景 大对象的创建. 优点 1.可以在运行时刻增加和删除产品 2.可以改变值或结构 ...
- 设计模式系列之原型模式(Prototype Pattern)——对象的克隆
说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...
- 六个创建模式之原型模式(Prototype Pattern)
定义: 使用原型实例指定创建对象的种类,并通过拷贝这个原型的属性创建新的对象. 结构图: Prototype:抽象原型类,声明克隆方法的接口,并是所有原型类的公共父类.在Java中,Object类为该 ...
- [工作中的设计模式]原型模式prototype
一.模式解析 提起prototype,最近看多了js相关的内容,第一印象首先是js的原型 var Person=function(name){ this.name=name; } Person.pro ...
随机推荐
- babel安装
大家都知道目前ES6不是浏览器全部都是支持的,所以要通过转码器先进行转码然后再编译代码.小心在学习ES6之前先安装了babel转码器,虽然当时安装的时候困难重重,遗憾的是没有把解决方案总结一下,别人询 ...
- 基于web工作流开发
目前在研发基于web工作流的开发 什么是工作流? 工作流简言之就是: 1.反应业务流程的计算机化的模型. 2.一类能够完全或者部分自动执行的经营过程:(为了提高效率,实现自动化). 3.任务.活动及活 ...
- Eclipse 下如何引用另一个项目的资源文件
为什么要这么做?可参考:Eclipse 下如何引用另一个项目的Java文件 下面直接说下步骤:(项目A 引用 项目B的资源文件) 1.右键 项目A,点击菜单 Properties 2.在弹出的框中,点 ...
- env1
给新手参考的Cadence Allegro快捷键 原文链接:http://www.eda365.com/thread-30935-1-1.html 发上我的快捷键给新手参考,我也是在LULU给我的EN ...
- Finalization
1.what is the main disadvantage of garbage collection? Typically, garbage collection has certain dis ...
- 函数buf_pool_init
/********************************************************************//** Creates the buffer pool. @ ...
- 【笨嘴拙舌WINDOWS】设备无关图(*.bmp)
设备无关图在windows上面就是一个扩展名为.bmp的文件.我们知道每一种文件都是一个二进制流,只是这个二进制流的开头几个字节是规定了文件的格式..bmp的文件格式如下 “其中信息头是windows ...
- Android中使用ListView实现分页刷新(线程休眠模拟)(滑动加载列表)
当要显示的数据过多时,为了更好的提升用户感知,在很多APP中都会使用分页刷新显示,比如浏览新闻,向下滑动到当前ListView的最后一条信息(item)时,会提示刷新加载,然后加载更新后的内容.此过程 ...
- 漫游kafka实战篇之搭建Kafka开发环境
上篇文章中我们搭建了kafka的服务器,并可以使用Kafka的命令行工具创建topic,发送和接收消息.下面我们来搭建kafka的开发环境. 添加依赖 搭建开发环境需要引入kafka的jar包 ...
- HDU 5273 Dylans loves numbers(水题)
题意:给出一个0≤N≤1018,求其二进制中有几处是具有1的,假设相连的1只算1处,比如1101011就是3处. 思路:一个个数,当遇到第一个1时就将flag置为1:当遇到0就将flag置为0.当遇到 ...