相信大多数的人都看过《西游记》,对孙悟空拔毛变出小猴子的故事情节应该都很熟悉。孙悟空可以用猴毛根据自己的形象复制出很多跟自己一模一样的小猴兵出来,其实在设计模式中也有一个类似的模式,我们可以通过一个原型对象来克隆出多个一模一样的对象,这个模式就是原型模式。

一 大同小异的工作周报

  M公司一直在使用自行开发的一个OA系统进行日常工作办理,但在使用过程中,越来越多的人对工作周报的创建和编写模块产生了抱怨。追其原因,M公司的OA管理员发现,由于某些岗位每周工作存在重复性,工作周报内容都大同小异,如下图所示:

  这些周报只有一些小地方存在差异,但是现行系统每周默认创建的周报都是空白报表,因此用户只能通过重新输入或不断地复制与粘贴来填写重复的周报内容,极大地降低了工作效率,浪费宝贵的时间。如何快速创建相同或者相似的工作周报,成为了M公司软件开发人员的一个新问题。

  M公司开发人员经过分析,决定按照以下思路对工作周报模块进行重新设计:

  (1)除了允许用户创建新周报外,还允许用户将创建好的周报保存为模板(也就是原型)。

  (2)用户在再次创建周报时,可以创建全新的周报,还可以选择合适的模板复制生成一个相同的周报,然后对新生成的周报根据实际情况进行修改,产生新的周报。

二 原型模式概述

2.1 关于原型模式

  原型模式的原理很简单,将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象克隆自己来实现创建过程。

原型模式(Prototype):使用原型实例指定创建对象的种类,并且通过拷贝这些原 型创建新的对象。原型模式是一种对象创建型模式。

  需要注意的是,通过克隆方法所创建的对象时全新的对象。

2.2 类图

  

2.3 代码实现

2.3.1 抽象克隆类

class AbstractClone
{
protected:
AbstractClone()
{
//cout << "AbstractClone Construct" << endl;
} public:
~AbstractClone()
{
//cout << "AbstractClone Deconstruct" << endl;
} virtual AbstractClone* Clone() = ;
virtual void PrintWeekly() = ;
};

2.3.2 周报类

class CWeeklyClone : public AbstractClone
{
public:
/*CWeeklyClone()
{
cout << "CWeeklyLogClone Construct" << endl;
}*/ CWeeklyClone(string strName="", string strDate="", string strContent="", CAttachment *pAttachment=NULL)
{
//cout << "CWeeklyLogClone Construct" << endl; m_strName = strName;
m_strDate = strDate;
m_strContent = strContent;
if (pAttachment!= NULL)
{
m_pAttachment = new CAttachment(*pAttachment);
}
else
{
m_pAttachment = NULL;
} }
CWeeklyClone(CWeeklyClone& other)
{
// 拷贝构造函数需要注意深拷贝和浅拷贝的问题
m_strName = other.m_strName;
m_strDate = other.m_strDate;
m_strContent = other.m_strContent; if (other.m_pAttachment != NULL)
{
// 浅拷贝方式
// m_pAttachment = other.m_pAttachment;
// 深拷贝方式
m_pAttachment = new CAttachment(*other.m_pAttachment); }
else
{
m_pAttachment = NULL;
}
//cout << "CWeeklyClone CopyConstruct" << endl;
} ~CWeeklyClone()
{
if (m_pAttachment != NULL)
{
delete m_pAttachment;
m_pAttachment = NULL;
}
//cout << "CWeeklyLogClone Deonstruct" << endl;
} CWeeklyClone* Clone()
{
return new CWeeklyClone(*this);
} void SetName(string strName)
{
m_strName = strName;
} void SetDate(string strDate)
{
m_strDate = strDate;
}
void SetContent(string strContent)
{
m_strContent = strContent;
}
void SetAttachment(CAttachment *pAttachment)
{
if (m_pAttachment != NULL)
{
m_pAttachment = pAttachment;
}
}
CAttachment *GetAttachment()
{
return m_pAttachment;
}
void PrintWeekly()
{
cout << "start:------------M公司个人工作周报------------" << endl;
cout << "周次:" << m_strDate <<endl;
cout << "员工:" << m_strName <<endl;
cout << "内容:" << m_strContent << endl;
if (m_pAttachment != NULL)
cout << "附件:" << m_pAttachment->m_strContent << endl; cout << "end:------------M公司个人工作周报------------" << endl;
}
private:
string m_strName;
string m_strDate;
string m_strContent; CAttachment *m_pAttachment;
};

2.3.3 附件类

#include <string>
#include <iostream>
using namespace std; // 附件类
class CAttachment
{
public:
CAttachment(string strContent="")
{
m_strContent = strContent;
//cout << "CAttachment CopyConstruct" << endl;
}
CAttachment(CAttachment &other)
{
m_strContent = other.m_strContent;
//cout << "CAttachment CopyConstruct" << endl;
}
~CAttachment()
{
//cout << "CAttachment Deonstruct" << endl;
} public:
string m_strContent;
};

2.4 测试

#include "stdio.h"

#include "prototype.h"

void main()
{
// 创建附件
CAttachment *pAttachment = new CAttachment("附件:紫贝龙二号文件"); // 创建周报
CWeeklyClone *pWeekly1 = new CWeeklyClone("张林", "第一周", "ddcpy模块单元测试", pAttachment);
pWeekly1->PrintWeekly(); CWeeklyClone *pWeekly2 = pWeekly1->Clone();
pWeekly2->SetDate("第二周");
pWeekly2->PrintWeekly(); // 判断周报是否相同
cout << "深拷贝模式下判断周报和附件是否相同:" << endl;
pWeekly1==pWeekly2 ? (cout << "周报相同"<< endl):(cout << "周报不相同" << endl);
pWeekly1->GetAttachment()==pWeekly2->GetAttachment() ? (cout << "附件相同"<< endl):(cout << "附件不相同" << endl);
return;
}

三 原型模式总结

3.1 主要优点

  (1)当创建新的对象实例较为复杂时,使用原型模式可以简化对象的创建过程,通过复制一个已有的实例可以提高新实例的创建效率。

  (2)可以使用深复制的方式保存对象的状态。将对象复制一份并将其状态保存起来,以便于在使用的时候使用,比如恢复到某一个历史状态,可以辅助实现撤销操作。

3.2 主要缺点

  (1)需要为每一个类配备一个克隆方法,而且该克隆方法位于一个类的内部,当对已有的类进行改造时,需要修改源代码,违背了开闭原则

  (2)为了支持深复制,当对象之间存在多重嵌套引用关系时,每一层对象都必须支持深复制,实现起来可能比较麻烦。

3.3 应用场景

  最主要的应用场景就在于 创建新对象成本较大(例如初始化需要占用较长的时间,占用太多的CPU资源或者网络资源),新的对象可以通过原型模式对已有对象进行复制来获得。如果是相似对象,则可以对其成员变量稍作修改。

设计模式之原型(prototype)模式的更多相关文章

  1. 设计模式C++描述----08.原型(Prototype)模式

    一. 概述 定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 换句话说,就是不用重新初始化对象,而是动态地获得对象运行时的状态. 再说明白点,就是要一个拷贝过构造函数类似功能的接 ...

  2. Java 实现原型(Prototype)模式

    public class BaseSpoon implements Cloneable {//spoon 匙, 调羹 String name; public String getName() { re ...

  3. 原型(Prototype)模式

    原型模式属于对象的创建模式.通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象.这就是原型模式的用意.原型模式的结构 原型模式要求对象实现一个可以“克隆 ...

  4. 设计模式--原型(Prototype)模式

    写这些也许有人认为“为了模式而模式”.Insus.NET所想到的,每个大师成为大师之前,也许都得这样做. 走路,从小就开始学,直至现在,谁还不是为了走路而走路?一直重复着...... 很多人没有分享自 ...

  5. 六、原型(Prototype)模式

    原型模式是对象的创建模式,通过给出一个原型对象来指明所要创建的对象的类型.然后用复制这个原型对象的方法来创建出更多同类型的对象. 原型模式可以不用重新初始化对象,而动态的获取对象运行时的状态.使用原型 ...

  6. 克隆复制可使用原型( Prototype)设计模式

    今天有学习设计模式的原型(Prototype)<设计模式--原型(Prototype)模式>http://www.cnblogs.com/insus/p/4152773.html .为了加 ...

  7. 设计模式_11_原型模式(prototype)深拷贝、浅拷贝

    设计模式_11_原型模式(prototype) 浅拷贝: package designPatternOf23; /** * 定义:用原型实例,指定创建对象的种类,并通过拷贝这些原型创建新的对象 * P ...

  8. [设计模式] 4 原型模式 prototype

    设计模式:可复用面向对象软件的基础>(DP)本文介绍原型模式和模板方法模式的实现.首先介绍原型模式,然后引出模板方法模式. DP书上的定义为:用原型实例指定创建对象的种类,并且通过拷贝这些原型创 ...

  9. 乐在其中设计模式(C#) - 原型模式(Prototype Pattern)

    原文:乐在其中设计模式(C#) - 原型模式(Prototype Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 原型模式(Prototype Pattern) 作者:weba ...

  10. C#设计模式之六原型模式(Prototype)【创建型】

    一.引言 在开始今天的文章之前先说明一点,欢迎大家来指正.很多人说原型设计模式会节省机器内存,他们说是拷贝出来的对象,这些对象其实都是原型的复制,不会使用内存.我认为这是不对的,因为拷贝出来的每一个对 ...

随机推荐

  1. javaEE中的hibernate配置笔记

    0 从web.xml出发 项目中用Spring整合Hibernate,Spring贯穿整个项目,所以先看看Spring在哪一步整合了Hibernate.先看部分web.xml. 在context-pa ...

  2. java byte为何范围是-128~127

    从我们接触Java的时候,就被告知基础类型byte是一个字节,占8位,表示的范围是-128~127.那么为什么会这个范围呢?   咱们先回顾一下计算机基础: 1. 在计算机内部数据的存储和运算都采用二 ...

  3. SVN插件下载地址及更新地址

    SVN插件下载地址及更新地址,你根据需要选择你需要的版本.现在最新是1.8.xLinks for 1.8.x Release:Eclipse update site URL: http://subcl ...

  4. linux根分区满了如何处理,查找大文件方法

    一:如果linux根分区使用量达到100%,会造成如下现象: root不能登录 系统不能正常启动 二:通过命令查找根分区内的大文件 du -sh /* 2>/dev/null | sort -h ...

  5. [nowcoder]因数个数和

    链接:https://www.nowcoder.com/acm/contest/158/A 考虑每个数对答案的贡献,所以答案就是$\sum_{i=1}^{n}{\lfloor\frac{n}{i}\r ...

  6. grep 使用场景

    (1)结合find命令和管道   你的一个音乐文件夹里有多种格式的文件,而你只想找到艺术家jay的mp3文件,并且不含有任何的混合音轨 find . -name "*mp3" | ...

  7. bootstrap下拉列表重置联动

    /**添加&修改时--获取机柜号**/ function BindSelectJgh(jiguiColumnIdD, jiguiNumberIdD) { var jid = !jiguiCol ...

  8. HUE中oozie执行shell

    Oozie执行Shell,传入参数1. 新建一个workflow 2. 拖入一个shell 3. shell脚本如下 #!/bin/sh sqoop import --connect jdbc:mys ...

  9. HttpServletResponse 的 sendError( )方法以及常用的HttpServletResponse常量级错误代码

    HttpServletResponse 的 sendError( )方法以及常用的HttpServletResponse常量级错误代码   转载:http://hi.baidu.com/yanfei_ ...

  10. DPDK l2fwd

    dpdk的l2fwd主要做二层转发,代码分析如下. #include <stdio.h> #include <stdlib.h> #include <string.h&g ...