1、出现原因
在软件系统中,经常面临着“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是它们却拥有比较稳定一致的接口。
如何应对这种变化?如何向“客户程序(使用这些对象的程序)”隔离出“这些易变对象” ,从而使得“依赖这些易变对象的客户程序”不随着需求改变而改变?
2、意图:
使用原型实例指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。(将相同的部分进行赋值拷贝,不同的部分需要客户端自己决定)
3、结构图
4、代码演示
举例:比如楼房的基本信息是相同的,但是他们的门牌号码是不同的,需要客户自己决定的。
//原型接口
public interface IBuildingPrototype
{
string BuildingName { set; get; }
string BuildingNo { set; get; }
IBuildingPrototype Clone();
}
//实现原型接口的类
public class Building : IBuildingPrototype
{
public string BuildingName
{
get;
set;
} public string BuildingNo
{
get;
set;
} public IBuildingPrototype Clone()
{
Building building = new Building();
building.BuildingName = this.BuildingName;
return building;
}
}
实现Prototype模式的代码
客户端调用代码:
Building b1 = new Building();
b1.BuildingName = "小别墅";
b1.BuildingNo = "B1203";
IBuildingPrototype b2 = b1.Clone();
b2.BuildingNo = "B1230";
Console.WriteLine(b2.BuildingName+":"+b2.BuildingNo);
使用.Net内部的原型模式的ICloneable接口实现版本
public class BuildingIclone : ICloneable
{
public string BuildingName { set; get; }
public string BildingNo { get; set; }
public object Clone()
{
BuildingIclone building = new BuildingIclone();
building.BuildingName = this.BuildingName;
return building;
}
}
5、深拷贝和浅拷贝
提到拷贝:就要想到深拷贝和浅拷贝,下面就来讲解他们之间的区别:
他们之间的区别是体现在他们之中的 引用类型的 属性的 拷贝方式,其他值类型和string类型的属性只是直接拷贝数值:
浅拷贝:只是拷贝 引用类型的引用指针,新拷贝出来的实例的此属性还是指向原来的实例的属性的“地址”。
深拷贝:是将引用类型的属性 从新在内存中 创建一份 然后赋值给新拷贝到实例对应的属性。
在.Net中实现浅拷贝的方式Object.MemberwiseClone();
实现深拷贝要自己写代码了,实现的方式有两种:1)将浅拷贝来的实例的引用类型的属性在从新赋值一个新的从内存中创建的实例。
2)使用序列化的方式实现深拷贝(将浅拷贝的实例进行序列化,然后再反序列化得到深拷贝的实例)
代码来演示:
//下面演示 :浅拷贝和深拷贝的区别
[Serializable]
public class WorkExperience : ICloneable
{
public string CompanyName { get; set; } public int Time { get; set; } public object Clone()
{
return this.MemberwiseClone();
} public override string ToString()
{
return string.Format("在{0}公司工作了{1}年",CompanyName,Time);
}
} [Serializable]
public class Worker : ICloneable
{
public string Name { get; set; } public int Age { get; set; } public WorkExperience WorkExprien { set; get; } //浅拷贝
public Worker QianClone()
{
return (Worker)this.MemberwiseClone();
} //深拷贝(将浅拷贝的实例的引用类型属性从新赋值的方式)
public object Clone()
{
Worker worker = (Worker)this.MemberwiseClone();
worker.WorkExprien = (WorkExperience)this.WorkExprien.Clone();
return worker;
} //深拷贝(序列化版本),要将要被序列化的类打上Serializable的特性
public Worker ShenClone()
{
Worker worker = (Worker) this.MemberwiseClone();
BinaryFormatter binary = new BinaryFormatter();
using (Stream stream = new MemoryStream())
{
binary.Serialize(stream, this);
stream.Position = ;//将当前流 重新定位,,否则会报错:“在分析完成之前就遇到流结尾。”
return (Worker) binary.Deserialize(stream);
}
} }
深拷贝和浅拷贝
测试代码:
Worker worker = new Worker()
{
Name = "小明",
Age = ,
WorkExprien = new WorkExperience() { CompanyName="百度",Time=}
}; Worker w1 = worker.QianClone();//浅拷贝
Worker w2 = (Worker)worker.Clone();//深拷贝
Worker w3 = worker.ShenClone();//序列化版本的深拷贝
Console.WriteLine(worker.WorkExprien.Equals(w1.WorkExprien));//True
Console.WriteLine(worker.WorkExprien.Equals(w2.WorkExprien));//False
Console.WriteLine(worker.WorkExprien.Equals(w3.WorkExprien));//False
测试代码
6、.Net中的原型模式
1》就是上面提到的ICloneable接口
2》DataSet
Clone()方法:浅拷贝:只复制表的结构,不复制表的数据
Copy()方法:深拷贝:既复制表的结构,又复制表的数据
7、实现要点
1、产品的创建和初始化在类的Clone方法中完成
2、浅复制与深复制的区别
3、需要深复制的场合需要开发人员根据需要实现(在重写的 Clone 里 将引用类型 成员进行复制)
4、有些情况下Clone功能不容易实现,特别是遇到对象的循环引用时(例如:A关联B,同时B也关联A:就是A中有B,同时B中也有A。这样就会造成,A中的Clone克隆的时候,要将 B进行克隆,同时在 B的Clone里面进行 克隆的时候A也就被同时复制了,所以会一直循环复制下去)
8、效果
在运行时增加或删除产品:只要通过客户原型实例即可将新产品类型增加到系统中,例如组态软件中工具箱中的每个工具可以对应一个注册的原型对象,可以通过增加原形对象扩展工具箱。
很容易地创建复杂的对象:在图形编辑和组态等软件中,经常需要创建复杂的图元。这些图元是由简单图元组成的,采用原型模式可以很容易地将复杂图元作为一般图元来使用,使软件的工具箱具有自扩展功能
9、适用性:
1、当一个系统应该独立于产品的创建、构成和表示时,可以使用原型模式。
2、在使用时,我们可以用一些原型对象来代替生成相应对象的工厂对象,并且可以使拷贝、粘贴等操作独立于需要复制的对象。
10、总结
1、Prototype模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系(使用者不用关心,类内部的具体情况,直接复制就可以了),它同样要求这些“易变类”拥有“稳定的接口”。
2、Prototype模式对于“如何创建易变类的实体对象”采用“原型克隆”的方法来做,它使得我们可以非常灵活地动态创建“拥有某些稳定接口”的新对象——所需工作仅仅是注册一个新的对象(即原型)(只要已经创建一个就可以了),然后在任何需要的地方不断地Clone。
3、Prototype模式中的Clone方法可以利用.NET中的Object类的MemberwiseClone()方法(浅拷贝)或者序列化来实现深拷贝。
设计模式之原型模式(Prototype)的更多相关文章
-
乐在其中设计模式(C#) - 原型模式(Prototype Pattern)
原文:乐在其中设计模式(C#) - 原型模式(Prototype Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 原型模式(Prototype Pattern) 作者:weba ...
-
二十四种设计模式:原型模式(Prototype Pattern)
原型模式(Prototype Pattern) 介绍用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象.示例有一个Message实体类,现在要克隆它. MessageModel usin ...
-
[设计模式] 4 原型模式 prototype
设计模式:可复用面向对象软件的基础>(DP)本文介绍原型模式和模板方法模式的实现.首先介绍原型模式,然后引出模板方法模式. DP书上的定义为:用原型实例指定创建对象的种类,并且通过拷贝这些原型创 ...
-
设计模式 笔记 原型模式 prototype
//---------------------------15/04/07---------------------------- //prototype 原型模式--对象创建型模式 /* 1:意图: ...
-
python 设计模式之原型模式 Prototype Pattern
#引入 例子1: 孙悟空拔下一嘬猴毛,轻轻一吹就会变出好多的孙悟空来. 例子2:寄个快递下面是一个邮寄快递的场景:“给我寄个快递.”顾客说.“寄往什么地方?寄给……?”你问.“和上次差不多一样,只是邮 ...
-
【UE4 设计模式】原型模式 Prototype Pattern
概述 描述 使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.如孙悟空猴毛分身.鸣人影之分身.剑光分化.无限剑制 原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象, ...
-
【设计模式】—— 原型模式Prototype
前言:[模式总览]——————————by xingoo 模式意图 由于有些时候,需要在运行时指定对象时哪个类的实例,此时用工厂模式就有些力不从心了.通过原型模式就可以通过拷贝函数clone一个原有的 ...
-
创建型设计模式之原型模式(Prototype)
结构 意图 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 适用性 当要实例化的类是在运行时刻指定时,例如,通过动态装载:或者 为了避免创建一个与产品类层次平行的工厂类层次时:或 ...
-
设计模式五: 原型模式(Prototype)
简介 原型模式是属于创建型模式的一种,是通过拷贝原型对象来创建新的对象. 万能的Java超类Object提供了clone()方法来实现对象的拷贝. 可以在以下场景中使用原型模式: 构造函数创建对象成本 ...
-
设计模式之原型模式(prototype)
原理:拷贝自身对象实际上就是调用的拷贝构造函数,注意事项是这里的拷贝是深拷贝,即需要拷贝指针所指的内容 #include <stdio.h> #include <memory> ...
随机推荐
-
Visual Studio 自定义控件不显示在工具箱
工具=>选项=>Windows窗体设计器=>常规=>AutoToolBoxPopulate=>True
-
理解C#中的“静态”
一.静态成员 1.通过static关键字修饰,是属于类,实例成员属于对象,在这个类第一次加载的时候,这个类下面的所有静态成员会被加载. 2.静态成员只被创建一次,所以静态成员只有一份,实例成员有多少个 ...
-
IOS视图旋转可放大缩小
- (IBAction)hideBut:(id)sender { if (self.flg) { [UIView animateWithDuration:0.3 animations:^{ self. ...
-
如何删除MyEclipse(eclipse)中不需要的workspace
在安装目录下,打开eclipse/configuration/.settings,用记事本打开org.eclipse.ui.ide.prefs文件 #Wed Mar 11 14:41:21 CST 2 ...
-
【POJ2352】【树状数组】Stars
Description Astronomers often examine star maps where stars are represented by points on a plane and ...
-
css 问题总结
background: <color> <image> <position> <attachment> <repeat>本文来自:佳木中国( ...
-
ZOJ 3795 Grouping(Tarjan收缩点+DAG)
Suppose there are N people in ZJU, whose ages are unknown. We have some messages about them. The i-t ...
-
mysql change master导致gtid丢失
change master导致gtid丢失从innobackupex恢复导致binlog的拉取位置会导致主备gtid不一致.此类错误通过构造空事务方式无法修复.此时就需要change master 方 ...
-
AMDP + XSLX Workbench 报表开发模式
本文介绍了我和同事通过使用AMDP + XSLX Workbench缩短报表开发周期.分离数据查询处理逻辑和前端展示工作的经验.欢迎讨论. 前言 最近接到了一套人力资源报表的开发需求,需要以EXCEL ...
-
修改Lotus notes默认浏览器
notes收到的邮件里面的链接,点了以后会自动在notes里打开,但notes很弱,加载页面总是有问题.怎么才能让他默认用ie浏览器打开呢,怎么设置,请教达人. 右下角有个office->Edi ...