C#设计模式03-原型模式
来源:互联网 发布:网络听课神器 编辑:程序博客网 时间:2024/04/27 22:30
好久没有写博客了,因为过年实在太忙了,家里也没有网络,今天第一天上班就先写一篇吧。话不多说,今天要写的内容是:原型模式,它也是创建型模式中的一种
首先来看定义:使用原型实例指定待创建对象的类型,并且通过复制这个原型来 创建新的对象。
理解定义之前先看一幅图:
孙悟空可以变出很多个和自己一模一样的猴子,这里的孙悟空就是原型类,原型类里面有一个Clone()方法可以复制他自己。有了这个方法他就可以自我复制出很多小猴子。原型模式和孙悟空自我复制自己这个模式差不多。
接下来我们就来看看原型模式的中的三种角色:
(1)Prototype(抽象原型类):这个类声明克隆(复制)方法(也就是Clone()方法),是所有具体原型类的父类,它可以是抽象类,接口或者具体的实现类
(2)ConcretePrototype(具体原型类):这个类实现(继承)抽象原型类,实现(重写)Clone方法以返回自己的一个克隆对象
(3)Client(客户端类):这个类通过调用Clone方法来克隆对象,返回值为Prototype
在介绍原型模式之前,有两个概念需要解释一下,也就是深克隆(深复制)和浅克隆(浅复制)。我们知道,C#中,值类型的数据存放在内存栈空间中,而引用类型存放在内存堆空间中,并且在栈空间上保存了该对象的引用地址。执行浅克隆操作时,会复制原型对象本身和原型对象中包含的值类型成员,而引用类型并没有被复制,仅仅复制了引用类型的地址。对克隆对象中引用类型的操作将直接影响原型对象。 而执行深克隆操作时,不仅复制原型对象本身和原型对象中包含的值类型成员,而且会复制引用类型,所以对克隆对象中引用类型的操作不会影响到原型类型。
C#中Object类型的MemberwiseClone方法可以帮助我们实现浅复制,而要想实现深复制的话,可以通过实现ICloneable接口来手动创建当前对象的副本。
接下来我们先实现浅克隆,因为它比较简单。
假设现在有一个客户管理系统,有一个客户类Customer,类里面有name字段表示客户名称,age字段表示客户年龄,还有一个Adress类型的成员变量表示客户的地址。
现在通过原型模式来浅复制客户类。
首先是我们的客户地址Adress类
namespace 原型模式{ public class Adress { public string province;//客户所在省份 public string county;//客户所在县名称 //..其他的村,街道等省略 public string postCode;//邮编 }}
然后是我们的客户类Customer
namespace 原型模式{ public class Customer//客户类(具体原型类) { public string name;//客户姓名 public string Name { get { return name; } set { name = value; } } private int age; public int Age { get { return age; } set { age = value; } } public Adress adress; //使用MemberwiseClone方法实现浅克隆 public Customer Clone() { return this.MemberwiseClone() as Customer; } }}
最后是我们的客户端类
namespace 原型模式{ class Program { static void Main(string[] args) { Customer c = new Customer(); Adress adress = new Adress() { province="山西",county="河津", postCode="043300"}; c.Name = "曹瑞鹏"; c.adress = adress; Customer copy = c.Clone(); Console.WriteLine("客户对象是否相同:{0}",c==copy); Console.WriteLine("地址是否相同:{0}", c.adress == copy.adress); Console.WriteLine("客户年龄是否相同:{0}", ReferenceEquals(c.Age, copy.Age)); Console.WriteLine("客户姓名是否相同:{0}", ReferenceEquals(c.Name, copy.Name)); Console.ReadLine(); } }}
运行结果如下:
从运行结果上可以清楚的看到,客户对象本身和客户年龄这两个变量都不相同了(也就是他们在内存中的地址不一致了)。而作为引用类型的地址和姓名这两个变量在内存中的地址是相同的,所以引用类型并没有被复制。这个就是浅复制。
Object的ReferenceEquals方法(静态方法)用于测试两个引用是否指向同一个类的实例,也就是是否指向同一个地址。
然后我们来实现深克隆,深克隆就是可以通过实现ICloneable接口来手动实现克隆
地址类Adress和上面的一样,客户端类和客户类需要修改一下
namespace 原型模式{ public class Customer:ICloneable//客户类(具体原型类) { public string name;//客户姓名 public string Name { get { return name; } set { name = value; } } private int age; public int Age { get { return age; } set { age = value; } } public Adress adress; public object Clone()//深克隆方法 { Adress adress = new Adress() { province = "北京", county = "海淀", postCode = "002335" }; Customer copy = this.MemberwiseClone() as Customer; copy.adress = adress; copy.Name = "曹瑞鹏"; return copy; } }}
namespace 原型模式{ class Program { static void Main(string[] args) { Customer c = new Customer(); Customer copy = c.Clone() as Customer; Console.WriteLine("客户对象是否相同:{0}",c==copy); Console.WriteLine("地址是否相同:{0}", c.adress == copy.adress); Console.WriteLine("客户年龄是否相同:{0}", ReferenceEquals(c.Age, copy.Age)); Console.WriteLine("客户姓名是否相同:{0}", ReferenceEquals(c.Name, copy.Name)); Console.ReadLine(); } }}
运行结果如下:
从运行结果可以看得出来,客户姓名和客户地址都成了false,而在浅复制中他们的比较结果是true。这就说明深复制操作会复制引用类型。
除了可以通过实现ICloneable接口达到深复制之外,还可以通过反射,序列化等方式实现深复制,有兴趣的朋友可以自己去查阅相关文档资料或者书籍。
到这里原型模式就给大家介绍完了,最后简单介绍一下原型模式的优缺点:
优点:复制对象的代价远小于创建对象的代价,所以当创建的对象较为复杂时,原型模式可以简化对象的创建过程
缺点:每个类里面必学有一个Clone克隆方法,当对现有的类进行改造时,需要修改Clone方法。这违背了开闭原则,扩展性也不是很好。同时深克隆的实现会比较麻烦,因为当当前对象之间存在多重嵌套的时候,每一层对象都必须支持深克隆。
原型类型的适用环境主要如下:
创建对象的成本较高,并且需要保存对象的状态信息,而这些状态信息的变化比较小。
下一篇文章将给大家介绍单例模式
- C#设计模式03-原型模式
- C#设计模式-原型模式
- 【C#设计模式-原型模式】
- C#设计模式--原型模式
- C#设计模式(原型模式)
- C#设计模式(四)原型模式
- 【设计模式】C#版原型模式
- c#设计模式==原型模式
- c#设计模式之原型模式
- 设计模式:原型模式
- 设计模式------原型模式
- 设计模式 原型模式
- 设计模式-【原型模式】
- 设计模式-原型模式
- 设计模式-原型模式
- 设计模式-原型模式
- 设计模式-原型模式
- 设计模式- 原型模式
- KETTLE——(二)数据抽取
- iOS --- 如何隐藏APP的statusBar
- C++ 学习(第一天)
- QT安装——Windows
- iOS之UIImage性能
- C#设计模式03-原型模式
- Cannot open Eclipse Marketplace
- 数据库复习三
- bzoj1597 土地购买
- Nodejs Assert
- 嵌入式代码结构
- 年终总结(15-16)
- 1006. Sign In and Sign Out (25)
- android:Activity启动模式之singleTop