用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。——DP

UML类图

模式说明

如果把在一张纸上手写一篇简历的过程看成是类的实例化过程,那么通过原型模式创建对象的过程就是拿着这张纸到复印机上复印的过程。即原型模式中的一个对象可以自我克隆生成另一个对象,而无需再次通过类的初始化过程。由于克隆操作比较常见,.NET已经提供了ICloneable接口(包含唯一一个方法Clone),所以在.NET中,只要实现这个接口,就算实现原型模式了。

下面的示例中,定义了两个类,一个简历类和一个地址类,并且两个类都实现ICloneable接口。

    /// <summary>
/// 在.Net中提供了ICloneable接口,无需再定义一个父类
/// </summary>
class Resume : ICloneable
{
public string Name { get; set; } public int Age { get; set; } public Address Addr { get; set; } public string Remark { get; set; } public Resume(string name)
{
Addr = new Address();
this.Name = name;
} // 原型模式
public object Clone()
{
Resume resume = this.MemberwiseClone() as Resume; //.NET中可以用MemberwiseClone方法创建自身的浅表副本
resume.Addr = this.Addr.Clone() as Address; return resume;
} public override string ToString()
{
return string.Format("姓名:{0},年龄:{1},地址:{2}——{3}", Name, Age, Addr.City + Addr.Street, Remark);
}
} class Address : ICloneable
{
public string City { get; set; } public string Street { get; set; } //原型模式
public object Clone()
{
return this.MemberwiseClone();
}
}

对于原型模式的实现,要注意一点,就是复制的深度问题。由于MemberwiseClone方法,实现的是浅拷贝,即被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。这样如果Resume类的Clone方法直接返回this. MemberwiseClone(),那么新对象和原对象的Addr属性将引用相同的Address对象,这里对this. MemberwiseClone()返回的浅拷贝对象的Addr属性,再次进行一次克隆,以便对Resume对象的Clone操作后,能生成一个完全独立的对象。

这样在客户端调用时,就完全可以通过对象的克隆来创建更多的新对象:

        static void Main(string[] args)
{
/*
* 原型模式
* 复制简历
*
*
* 原型模式的实质是对于构造非常复杂的情况,比如在构造函数的时候
* 需要远程读取信息或者要完成许多复杂操作的时候 这时候用clone就会非常方便地获取其他实例的状态
*
*
* 用了DataTable的Clone方法就知道了,为什么DataTable要这个方法,原因是当得到一个DataTable对象的时候
* 又想创建一个一样的DataTable的话,如果没有Clone,那么就要创建Columns,这个是很麻烦的
* 但是有了Clone就很爽了,直接调用就行
*
*/ Resume resume1 = new Resume("我的简历模板");
resume1.Age = ; //梦想着还是18岁……
resume1.Addr.City = "湖州市";
resume1.Addr.Street = "二环西路";
resume1.Remark = "这份简历是自己留着,作为复印模板的。"; Resume resume2 = (Resume)resume1.Clone(); //对象克隆
resume2.Name = "苦哥";
resume2.Age = ;
resume2.Remark = "这是给软件公司的简历"; Resume resume3 = (Resume)resume2.Clone(); //对象克隆
resume3.Name = "苦哥大人";
resume3.Addr.City = "合肥市";
resume3.Addr.Street = "长江路";
resume3.Remark = "这是投到合肥的简历,写成住合肥,是不是会亲近点?"; Console.WriteLine(resume1.ToString());
Console.WriteLine(resume2.ToString());
Console.WriteLine(resume3.ToString()); Console.Read();
}

总结

原型模式的实现过程中,要知道两个概念:

  • 浅复制:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。
  • 深复制:把引用对象的变量指向复制过来的新对象,而不是原有的被引用的对象。

还有一点要考虑到的就是深复制的深度问题,如果对象引用的对象内,又包含了对其他对象的引用……这样在深复制时要考虑复制多少层的问题,对于这种情况,可以通过序列化与反序列化的方式,来达到对象深复制的目的。

参考

  1. 程杰老师  《大话设计模式》

设计模式——原型模式(Prototype)的更多相关文章

  1. PHP设计模式 原型模式(Prototype)

    定义 和工厂模式类似,用来创建对象.但实现机制不同,原型模式是先创建一个对象,采用clone的方式进行新对象的创建. 场景 大对象的创建. 优点 1.可以在运行时刻增加和删除产品 2.可以改变值或结构 ...

  2. [工作中的设计模式]原型模式prototype

    一.模式解析 提起prototype,最近看多了js相关的内容,第一印象首先是js的原型 var Person=function(name){ this.name=name; } Person.pro ...

  3. C#设计模式——原型模式(Prototype Pattern)

    一.概述 在软件开发中,经常会碰上某些对象,其创建的过程比较复杂,而且随着需求的变化,其创建过程也会发生剧烈的变化,但他们的接口却能比较稳定.对这类对象的创建,我们应该遵循依赖倒置原则,即抽象不应该依 ...

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

    场景分析: 前面我们提到,交易对象Trade,还有继承他的债券交易BondTrade.期货交易FutureTrade. 现在有一个需求,需要提供方法将交易拆分成多笔小交易. 代码如下(如果没有clon ...

  5. 设计模式——原型模式(Prototype Pattern)

    原型模式:用原型实例制定创建对象的种类,并且通过拷贝这些原型创建新的对象. UML 图: 原型类: package com.cnblog.clarck; /** * 原型类 * * @author c ...

  6. 大话设计模式--原型模式 Prototype -- C++实现

    1. 原型模式: 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象... 注意: 拷贝的时候是浅拷贝 还是 深拷贝, 来考虑是否需要重写拷贝构造函数. 关键在于: virtual Pro ...

  7. 设计模式--原型模式Prototype(创建型)

    一.原型模式 用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象.原型模式实现的关键就是实现Clone函数,还需要实现深拷贝. 二.UML类图 三.例子 //父类 class Resume ...

  8. 谈谈设计模式~原型模式(Prototype)

    返回目录 原型模式是创建型模式的一种,其特点在于通过“复制”一个已经存在的实例来返回新的实例(clone),而不是新建(new)实例.被复制的实例就是我们所称的“原型”,这个原型是可定制的. 原型模式 ...

  9. Net设计模式实例之原型模式( Prototype Pattern)

    一.原型模式简介(Brief Introduction) 原型模式(Prototype Pattern):用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象. Specify the kin ...

随机推荐

  1. Undefined exploded archive location(在myeclipse中TOMCAT不能发布程序。)

    原因:          在工程转移过程中,导致工程的配置文件出错: 解决方法:          1.在工程目录下的.mymetadata文件中可能webrootdir被改无效了(把下面内容拷到你的 ...

  2. Trilead,SSH2的Java调用

    最近项目要部署10台设备,如果每台设备都手动进行部署想想也是醉了. 因为之前一直使用SecurityFX以及SecurityCRT,所以考虑是否可以使用基于SSH2的类库来实现文件拷贝以及远程命令调用 ...

  3. phpMailer在CentOS 6.5下无法发送邮件的解决办法

    作者:ffsystem 网站在Windows平台上开发测试,完成了后同步到CentOS6.5 Nigix运行.发现phpMailer组件无法与SMTP服务器建立连接,导致无法发送邮件. 错误代码: p ...

  4. mybatis 学习一 总体概述

    mybatis使用起来不复杂,大体上来说,就是将db连接信息,所有的sql语句信息,都放到配置文件里面,然后去读配置信息,根据db信息,创建好session工厂,然后拿到sqlsession回话之后, ...

  5. GIF助手帮助说明

    生成的文件位置? 生成的GIF等文件存储在 /sdcard/gifdir/ 目录下. 为什么分享到微信.Twitter等平台失败? 微信.Twitter等平台对GIF文件大小有限制,微信限制为1MB, ...

  6. How to Write a Spelling Corrector用java 写拼写检查器 Java实现 以备查验

    import java.io.*;import java.util.*;import java.util.regex.*; class Spelling { private final HashMap ...

  7. Math类简介

    Math  abs max min 分别是绝对值 最大值,最小值 round 四舍五入 ceil ceil(32.6)  33.0 ceil(32.2) 33.0 返回大于该数值的较大的整数 与之相对 ...

  8. 06_android虚拟机介绍 05_sdkManager介绍

    如果你不对SDK Manager进行设置,它默认会去谷歌官网下载最新的内容.由于官网被墙了,要么你FQ要么去设置代理.通过代理去下载相关的内容. 每一个android版本都对应着一个API的版本号.如 ...

  9. Java之网络编程UDP和TCP

    注*部分转来的 第1章 网络通信协议 通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时需要遵守一定的规则,这就好比在道路中行驶的汽车一定要遵守交通规则一样.在计算机网 ...

  10. win7中配置eclipse连接Ubuntu内的hadoop

    Hadoop java 分布式 云计算 数据库 目录[-] 1.设置Ubuntu静态IP: 1)配置网卡参数到interfaces文件: 2)重启网卡: 2.配置Ubuntu的hosts: 3.配置V ...