设计模式——原型模式(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 ...
随机推荐
- XMPP群聊消息重复,自己收到自己发出的消息,群警告消息如何屏蔽
在XMPP的"groupchat"中,创建群的时候会收到群发的"This room is locked from entry until configuration is ...
- Guava手记
Cache Guava的Cache封装的功能比较全面,但是很多地方和设想的不太一样,最明显的就是RemovalListener,它并不是invalid之后就会被调用,因为在调用Cache的invali ...
- BZOJ3401:[USACO2009MAR]Look Up
浅谈栈:https://www.cnblogs.com/AKMer/p/10278222.html 题目传送门:https://lydsy.com/JudgeOnline/problem.php?id ...
- TVYJ1266:费解的开关
我对状态空间的理解:https://www.cnblogs.com/AKMer/p/9622590.html 题目传送门:http://www.joyoi.cn/problem/tyvj-1266 这 ...
- Python:模块详解及import本质
转于:http://www.cnblogs.com/itfat/p/7481972.html 博主:东大网管 一.定义: 模块:用来从逻辑上组织python代码(变量,函数,类,逻辑:实现一个功能), ...
- Trie(前缀树/字典树)及其应用
Trie,又经常叫前缀树,字典树等等.它有很多变种,如后缀树,Radix Tree/Trie,PATRICIA tree,以及bitwise版本的crit-bit tree.当然很多名字的意义其实有交 ...
- 二 vue环境搭建
一: 新建一个项目文件夹,命名为 vue-demo,cd到此文件夹,输入:vue init webpack vue-demo,回车,按照如下操作进行初始化: 2: 项目结构 3: 安装项目依赖的包 ...
- Android Studio的Android Monitor窗口中把标签拉出来之后放不回去的解决方法
不小心把下图方框中的logcat标签拖出来之后, 就变成了图2的浮动窗口,发现logcat标签怎么也弄不回原来窗口中的位置中. 其实解决方法很简单,只要拖住下图浮动窗口中红框位置的logcat标签,然 ...
- IIS应用池保持激活工具开发
之前的 开源一个定时任务调度器 webscheduler 中涉及的定时调用应用已经开始在正式环境中启用,发布到IIS下进行测试,发现一旦应用长时间没有访问(大约半个多小时)就会引发 Applicati ...
- 【原】spring jar 下载
作者:david_zhang@sh [转载时请以超链接形式标明文章] 链接:http://www.cnblogs.com/david-zhang-index/p/8098965.html 1.进入官网 ...