设计模式之原型(prototype)模式

时间:2022-12-09 18:37:51

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

一 大同小异的工作周报

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

设计模式之原型(prototype)模式

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

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

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

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

二 原型模式概述

2.1 关于原型模式

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

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

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

2.2 类图

  设计模式之原型(prototype)模式

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;
}

设计模式之原型(prototype)模式

三 原型模式总结

3.1 主要优点

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

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

3.2 主要缺点

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

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

3.3 应用场景

设计模式之原型(prototype)模式

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

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

  1. 设计模式C&plus;&plus;描述----08&period;原型&lpar;Prototype&rpar;模式

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

  2. Java 实现原型&lpar;Prototype&rpar;模式

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

  3. 原型&lpar;Prototype&rpar;模式

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

  4. 设计模式--原型&lpar;Prototype&rpar;模式

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

  5. 六、原型&lpar;Prototype&rpar;模式

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

  6. 克隆复制可使用原型&lpar; Prototype&rpar;设计模式

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

  7. 设计模式&lowbar;11&lowbar;原型模式(prototype)深拷贝、浅拷贝

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

  8. &lbrack;设计模式&rsqb; 4 原型模式 prototype

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

  9. 乐在其中设计模式&lpar;C&num;&rpar; - 原型模式&lpar;Prototype Pattern&rpar;

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

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

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

随机推荐

  1. Android开发之MVP模式的使用

    前几天发现,在Android项目代码里有一个Activity类行数居然有1000多行,而600行左右都是逻辑控制,真正和页面控件处理相关的代码不多,虽然可以用#region <>...#e ...

  2. MySQL 常见的sql命令

    注意事项: 1.sql 使用单引号来环绕文本值(大部分数据库系统也接受双引号).如果是数值,请不要使用引号. 一.数据库 1.创建数据库 CREATE DATABASE lesson ; 创建一个名字 ...

  3. jQuery Mobile 脚本加载问题

    刚开始使用jQuery Mobile,发现很多问题需要重新考虑,比如脚本加载问题. 在普通html中,如果a.html中有链接到b.html,b.html中有类似代码: $(document).rea ...

  4. &lbrack;Effective JavaScript 笔记&rsqb;第56条:避免不必要的状态

    API有时被归为两类:有状态的和无状态的.无状态的API提供的函数或方法的行为只取决于输入,而与程序的状态改变无关.字符串的方法是无状态的.字符串的内容不能被修改,方法只取决于字符串的内容及传递给方法 ...

  5. php 快速fork出指定个子进程

    $pids = array(); $child_pid = pcntl_fork(); if ($child_pid == -1) { throw new Exception( __METHOD__ ...

  6. freeCodeCamp&colon;Missing letters

    从传递进来的字母序列中找到缺失的字母并返回它. 如果所有字母都在序列中,返回 undefined. function fearNotLetter(str) { var arr = str.split( ...

  7. hdu5556 Land of Farms

    我对于题目的一种理解 改造农场 1.建新农场 在空的点选 2.重建旧农场 选一个点属于这个农场的地方都要选 最后的农场都不能相连 所以枚举旧农场的个数并进行二分图匹配 #include<bits ...

  8. java常使用的框架

    一.SpringMVC Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动 ...

  9. 1-web&period;xml配置说明

    编写第一个Servlet程序  重要的在于如何去配置项目中的web.xml文件 <servlet-class>  设置servlet程序全限定路径 也就是在项目的中路径 <servl ...

  10. Ubuntu中保存iptables防火墙规则

    Ubuntu中保存iptables防火墙规则的例子 打开防火墙 ufw disableufw statusufw enable ufw allow 22/tcp ufw reload iptables ...