文档章节

原型模式--prototype

r
 ranjiewen
发布于 2016/11/03 23:52
字数 1768
阅读 2
收藏 0
C++设计模式——原型模式

什么是原型模式?

在GOF的《设计模式:可复用面向对象软件的基础》中是这样说的:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。这这个定义中,最重要的一个词是“拷贝”,也就是口头上的复制,而这个拷贝,也就是原型模式的精髓所在。

举一个最简单的例子来说明原型模式:记得上小学的时候,老师把需要做的课外习题写到黑板上,而下面的我们都要把这些题抄写到自己的本子上,回家做好,第二天交上来,也就是每道题,全班50个人,每个人都要抄写一遍。按照现在的时间理论来说,就是浪费了50个人的时间。但是,那个时候条件限制,老师也是不得已而为之。现在好了,老师做一份电子版的习题,打印一份,然后拿着这份打印的原版,就可以复制出50份。

结合原型模式的概念进行分析,老师打印出来的那一份,就是“原型”,而复制出来的那50份,就是使用的“拷贝”。而原型模式就是这么简单的一个道理,通过现有的东西,再复制出一个来。

为什么要使用原型模式?

原型模式和建造者模式、工厂方法模式一样,都属于创建型模式的一种。简单的来说,我们使用原型模式,就是为了创建对象。但是,在以下场景下,使用原型模式是最好的选择:

  1. 当我们的对象类型不是开始就能确定的,而这个类型是在运行期确定的话,那么我们通过这个类型的对象克隆出一个新的对象比较容易一些;
  2. 有的时候,我们需要一个对象在某个状态下的副本,此时,我们使用原型模式是最好的选择;例如:一个对象,经过一段处理之后,其内部的状态发生了变化;这个时候,我们需要一个这个状态的副本,如果直接new一个新的对象的话,但是它的状态是不对的,此时,可以使用原型模式,将原来的对象拷贝一个出来,这个对象就和之前的对象是完全一致的了;
  3. 当我们处理一些比较简单的对象时,并且对象之间的区别很小,可能就几个属性不同而已,那么就可以使用原型模式来完成,省去了创建对象时的麻烦了;
  4. 有的时候,创建对象时,构造函数的参数很多,而自己又不完全的知道每个参数的意义,就可以使用原型模式来创建一个新的对象,不必去理会创建的过程,让创建过程见鬼去吧。

所以,在上述的的情况下,在设计的时候,适当的考虑一下原型模式,减少对应的工作量,减少程序的复杂度,提高效率。

用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(){}
    virtual Prototype* clone() = 0;
};
//实现
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;
    return 0;
}
上述代码实现了一个最简单的原型模式,但是已经将原型模式的基本实现原理展现出来了。而有的时候,当调用Clone获得了一个复制的对象以后,需要改变对象的状态,此时就可能需要在ConcretePrototype类中添加一个Initialize操作,专门用于初始化克隆对象。由于在Clone的内部调用的是复制构造函数,而此处又涉及到深复制和浅复制的问题。所以,在实际操作的过程中,这些问题,都需要进行仔细的考虑。

与其它创建型模式的比较

工厂方法模式、抽象工厂模式、建造者模式和原型模式都是创建型模式。工厂方法模式适用于生产较复杂,一个工厂生产单一的一种产品的时候;抽象工厂模式适用于一个工厂生产多个相互依赖的产品;建造者模式着重于复杂对象的一步一步创建,组装产品的过程,并在创建的过程中,可以控制每一个简单对象的创建;原型模式则更强调的是从自身复制自己,创建要给和自己一模一样的对象。

总结

原型模式作为创建型模式中最特殊的一个模式,具体的创建过程,是由对象本身提供,这样我们在很多的场景下可以很方便的快速的构建新的对象。但是,原型模式的最大缺点是继承原型的子类都要实现Clone操作,这个是很困难的。例如,当所考虑的类已经存在时就难以新增Clone操作。当内部包括一些不支持拷贝或者有循环引用的对象时,实现克隆可能也会很困难。说以说,每一种设计模式都有它的优点和缺点,在设计的时候,我们需要进行权衡各方面的因素,扬长避短。

本文转载自:http://www.cnblogs.com/ranjiewen/p/5901224.html

r
粉丝 1
博文 203
码字总数 28
作品 0
武汉
程序员
私信 提问
23种设计模式(5):原型模式

定义:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。 类型:创建类模式 类图: 原型模式主要用于对象的复制,它的核心是就是类图中的原型类Prototype。Prototype类需要具...

LCZ777
2014/07/05
52
0
设计模式7——Prototype设计模式

Prototype原型设计模式是指用原型实例指定创建对象的种类,并且通过拷贝这些原型来创建新的对象。Prototype原型模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何关于对象创建的...

小米米儿小
2013/12/11
60
0
Prototype(原型)设计模式之析

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。 Prototype原型模式是一种创建型设计模式,Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何...

欧阳俊文
2013/11/19
120
0
javascript 原型

什么是原型(prototype) 原型是javascript用来创建对象的一种设计模式。比较Java和javascript创建对象的区别。Java中创建对象的过程,先指定一个类型,然后通过类创建对象。类是对象的蓝图。...

sl_yang
2016/06/15
11
0
设计模式-原型模式

原型模式 原型模式的优点 使用场景 代码实现: 原型模式的注意点 使用原型模式不会调用类的构造方法. 深拷贝和浅拷贝 浅拷贝: 对值类型的成员变量进行值的复制,对引用类型的成员变量只复制引用...

wjk_snail
2016/03/17
9
0

没有更多内容

加载失败,请刷新页面

加载更多

川普给埃尔多安和内堪尼亚胡的信

任性 https://twitter.com/netanyahu/status/1186647558401253377 https://edition.cnn.com/2019/10/16/politics/trump-erdogan-letter/index.htm...

Iridium
22分钟前
10
0
golang-mysql-原生

db.go package mainimport ("database/sql""time"_ "github.com/go-sql-driver/mysql")var (db *sql.DBdsn = "root:123456@tcp(127.0.0.1:3306)/test?charset=u......

李琼涛
51分钟前
5
0
编程作业20191021092341

1编写一个程序,把用分钟表示的时间转换成用小时和分钟表示的时 间。使用#define或const创建一个表示60的符号常量或const变量。通过while 循环让用户重复输入值,直到用户输入小于或等于0的值...

1李嘉焘1
51分钟前
7
0
Netty整合Protobuffer

现在我们都知道,rpc的三要素:IO模型,线程模型,然后就是数据交互模型,即我们说的序列化和反序列化,现在我们来看一下压缩比率最大的二进制序列化方式——Protobuffer,而且该方式是可以跨...

算法之名
56分钟前
19
0
如何用C++实现栈

栈的定义 栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压...

BWH_Steven
今天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部