设计模式——原型模式(Prototype)
用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。——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();
}
总结
原型模式的实现过程中,要知道两个概念:
- 浅复制:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。
- 深复制:把引用对象的变量指向复制过来的新对象,而不是原有的被引用的对象。
还有一点要考虑到的就是深复制的深度问题,如果对象引用的对象内,又包含了对其他对象的引用……这样在深复制时要考虑复制多少层的问题,对于这种情况,可以通过序列化与反序列化的方式,来达到对象深复制的目的。
参考
- 程杰老师 《大话设计模式》
设计模式——原型模式(Prototype)的更多相关文章
- PHP设计模式 原型模式(Prototype)
定义 和工厂模式类似,用来创建对象.但实现机制不同,原型模式是先创建一个对象,采用clone的方式进行新对象的创建. 场景 大对象的创建. 优点 1.可以在运行时刻增加和删除产品 2.可以改变值或结构 ...
- [工作中的设计模式]原型模式prototype
一.模式解析 提起prototype,最近看多了js相关的内容,第一印象首先是js的原型 var Person=function(name){ this.name=name; } Person.pro ...
- C#设计模式——原型模式(Prototype Pattern)
一.概述 在软件开发中,经常会碰上某些对象,其创建的过程比较复杂,而且随着需求的变化,其创建过程也会发生剧烈的变化,但他们的接口却能比较稳定.对这类对象的创建,我们应该遵循依赖倒置原则,即抽象不应该依 ...
- 设计模式-原型模式(Prototype)
场景分析: 前面我们提到,交易对象Trade,还有继承他的债券交易BondTrade.期货交易FutureTrade. 现在有一个需求,需要提供方法将交易拆分成多笔小交易. 代码如下(如果没有clon ...
- 设计模式——原型模式(Prototype Pattern)
原型模式:用原型实例制定创建对象的种类,并且通过拷贝这些原型创建新的对象. UML 图: 原型类: package com.cnblog.clarck; /** * 原型类 * * @author c ...
- 大话设计模式--原型模式 Prototype -- C++实现
1. 原型模式: 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象... 注意: 拷贝的时候是浅拷贝 还是 深拷贝, 来考虑是否需要重写拷贝构造函数. 关键在于: virtual Pro ...
- 设计模式--原型模式Prototype(创建型)
一.原型模式 用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象.原型模式实现的关键就是实现Clone函数,还需要实现深拷贝. 二.UML类图 三.例子 //父类 class Resume ...
- 谈谈设计模式~原型模式(Prototype)
返回目录 原型模式是创建型模式的一种,其特点在于通过“复制”一个已经存在的实例来返回新的实例(clone),而不是新建(new)实例.被复制的实例就是我们所称的“原型”,这个原型是可定制的. 原型模式 ...
- Net设计模式实例之原型模式( Prototype Pattern)
一.原型模式简介(Brief Introduction) 原型模式(Prototype Pattern):用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象. Specify the kin ...
随机推荐
- 查看,上传crushmap命令
标签(空格分隔): ceph,ceph运维,crushmap 查看crushmap命令 从mon节点获取crushmap: # ceph osd getcrushmap -o crush.map 反编 ...
- openstack常见问题汇总
汇总下常见的问题以及解释下一些比较容易让人萌的参数配置等等 问题汇总1.使用纯文本模式进行复制粘贴,打死不要用word!!!可以解决绝大多数问题,如果你依然执迷不悟,那么就好自为之吧 2.创建路由器时 ...
- viewstate的基本用法
转自:http://www.cnblogs.com/ooip/p/4743536.html 在web窗体将控件属性设置为runat=server时,这个控件会被添加一个隐藏属性_ViewState,_ ...
- java高并发前言
- 卡特兰数&错排&一个一直记不住的公式
卡特兰数 公式:f(x)=f(2)*f(x-1)+f(3)*f(x-2)+......+f(x-1)*f(2) #include<iostream>#include<cstdlib& ...
- 8.bwapp亲测xxe漏洞
这几天在学习XXE漏洞,这里用靶机bwapp来练习一下这个漏洞,重在学习 xxe漏洞主要针对webservice危险的引用的外部实体并且未对外部实体进行敏感字符的过滤, 从而可以造成命令执行,目录遍历 ...
- 《鸟哥的Linux私房菜》读书笔记1
1.MBR 可以说是整个硬盘最重要的地方了,因为在 MBR 里面记录了两个重要的东西,分别是:开机管理程序,与磁盘分割表 ( partition table ).下次记得人家在谈磁盘分割的时候, 不要 ...
- idea中,使用Gradle创建的项目,如何变为web项目
当idea开发项目时,使用gradle构建项目,包引用完后,发现idea并没有正确识别项目为web项目. 主要有两点表现: 1. src/main/resources的resources目录没有或有但 ...
- Netty 线程模型与Reactor 模式
前言 Netty 的线程模型是基于NIO的Selector 构建的,使用了异步驱动的Reactor 模式来构建的线程模型,可以很好的支持成百上千的 SocketChannel 连接.由于 READ/W ...
- NPOI office操作
写excel FileStream file = new FileStream(@"test.xls",FileMode.Create); hssfworkbook.write(f ...