对原型对象的 浅复制 深复制
原型模式就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。
对于.NET而言,那个原型抽象类Prototype是用不着的,因为克隆是在是太常用了。所以.NET在System命令空间中提供了ICloneable接口,其中就就是唯一的一个方法Clone().这样你就只需要实现这个接口就可以完成原型模式了。
每New一次都需要执行一次构造函数,如果构造函数执行时间很长,多次执行这个初始化操作就太低效了。 一般在初始化的信息不发生变化的情况下,克隆是最好的方法。这既隐藏了对象创建的细节,又对性能是大大的提高。
不用重新初始化对象,而是动态地获得对象运行时的状态。
在一些特定场合,会经常涉及深复制或浅复制。比如,数据集对象DataSet,它就有Clone()方法和Copy()方法,Clone()方法用来复制DataSet的结构,但不复制DataSet的数据,实现了原型模式的浅复制。Copy()方法不但复制结构,也复制数据,起始就是实现了原型模式的深复制。
原型模式-基本代码:
using System;
using System.Collections.Generic;
using System.Text;namespace 原型模式
{class Program{static void Main(string[] args){ConcretePrototype1 p1 = new ConcretePrototype1("I");ConcretePrototype1 c1 = (ConcretePrototype1)p1.Clone();Console.WriteLine("Cloned: {0}", c1.Id);ConcretePrototype2 p2 = new ConcretePrototype2("II");ConcretePrototype2 c2 = (ConcretePrototype2)p2.Clone();Console.WriteLine("Cloned: {0}", c2.Id);// Wait for user Console.Read();}}//抽象原型abstract class Prototype{private string id;// Constructor public Prototype(string id){this.id = id;}// Property public string Id{get { return id; }}public abstract Prototype Clone();//克隆方法}//具体原型1class ConcretePrototype1 : Prototype{// Constructor public ConcretePrototype1(string id): base(id){}public override Prototype Clone(){// Shallow copy 浅层复制return (Prototype)this.MemberwiseClone();}}//具体原型2class ConcretePrototype2 : Prototype{// Constructor public ConcretePrototype2(string id): base(id){}public override Prototype Clone(){// Shallow copy 浅层复制return (Prototype)this.MemberwiseClone();}}}
简历的原型模式:
using System;
using System.Collections.Generic;
using System.Text;namespace 原型模式
{class Program //简历的原型模式{static void Main(string[] args){Resume a = new Resume("大鸟");a.SetPersonalInfo("男", "29");a.SetWorkExperience("1998-2000", "XX公司");Resume b = (Resume)a.Clone();b.SetWorkExperience("1998-2006", "YY企业");Resume c = (Resume)a.Clone();c.SetPersonalInfo("男", "24");/*大鸟 男 29工作经历:1998-2000 XX公司大鸟 男 29工作经历:1998-2006 YY企业大鸟 男 24工作经历:1998-2000 XX公司*/a.Display();b.Display();c.Display();Console.Read();}}//简历class Resume : ICloneable{private string name;private string sex;private string age;private string timeArea;private string company;public Resume(string name){this.name = name;}//设置个人信息public void SetPersonalInfo(string sex, string age){this.sex = sex;this.age = age;}//设置工作经历public void SetWorkExperience(string timeArea, string company){this.timeArea = timeArea;this.company = company;}//显示public void Display(){Console.WriteLine("{0} {1} {2}", name, sex, age);Console.WriteLine("工作经历:{0} {1}", timeArea, company);}public Object Clone(){return (Object)this.MemberwiseClone();}}}
浅复制 vs 深复制:
简历浅复制实现:
using System;
using System.Collections.Generic;
using System.Text;namespace 原型模式
{class Program{static void Main(string[] args){Resume a = new Resume("大鸟");a.SetPersonalInfo("男", "29");a.SetWorkExperience("1998-2000", "XX公司");Resume b = (Resume)a.Clone();b.SetWorkExperience("1998-2006", "YY企业");Resume c = (Resume)a.Clone();c.SetPersonalInfo("男", "24");c.SetWorkExperience("1998-2003", "ZZ企业");a.Display();b.Display();c.Display();Console.Read();}}//简历class Resume : ICloneable{private string name;private string sex;private string age;private WorkExperience work; //引用类型,浅复制public Resume(string name){this.name = name;work = new WorkExperience();}//设置个人信息public void SetPersonalInfo(string sex, string age){this.sex = sex;this.age = age;}//设置工作经历public void SetWorkExperience(string workDate, string company){work.WorkDate = workDate;work.Company = company;}//显示public void Display(){Console.WriteLine("{0} {1} {2}", name, sex, age);Console.WriteLine("工作经历:{0} {1}", work.WorkDate, work.Company);}public Object Clone(){return (Object)this.MemberwiseClone();}}//工作经历class WorkExperience{private string workDate;public string WorkDate{get { return workDate; }set { workDate = value; }}private string company;public string Company{get { return company; }set { company = value; }}}}
MemberwiseClone()方法是这样:如果字段是值类型的,则对该字段执行逐位复制,如果字段是引用类型,则复制引用但不复制引用的对象。因此院士对象及其复本引用同一对象。
MemberwiseClone()是浅表复制,所以对于值类型没有问题,对引用类型,就只是复制了引用,对引用的对象还是指向了原来的对象。多个引用都是最后一次设置,多个引用指向同一对象。
浅复制: 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。
深复制:把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。
深复制要深入到多少层,需要事先考虑好,而且要当心出现循环引用的问题,需要小心处理。
简历深复制的实现:
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;namespace 原型模式
{class Program{static void Main(string[] args){Resume a = new Resume("大鸟");a.SetPersonalInfo("男", "29");a.SetWorkExperience("1998-2000", "XX公司");Resume b = (Resume)a.Clone();b.SetWorkExperience("1998-2006", "YY企业");Resume c = (Resume)a.Clone();c.SetWorkExperience("1998-2003", "ZZ企业");a.Display();b.Display();c.Display();Console.Read();}}//简历class Resume : ICloneable{private string name;private string sex;private string age;private WorkExperience work;public Resume(string name){this.name = name;work = new WorkExperience();}private Resume(WorkExperience work){this.work = (WorkExperience)work.Clone();}//设置个人信息public void SetPersonalInfo(string sex, string age){this.sex = sex;this.age = age;}//设置工作经历public void SetWorkExperience(string workDate, string company){work.WorkDate = workDate;work.Company = company;}//显示public void Display(){Console.WriteLine("{0} {1} {2}", name, sex, age);Console.WriteLine("工作经历:{0} {1}", work.WorkDate, work.Company);}public Object Clone(){Resume obj = new Resume(this.work);obj.name = this.name;obj.sex = this.sex;obj.age = this.age;return obj;}}//工作经历class WorkExperience : ICloneable //实现克隆接口{private string workDate;public string WorkDate{get { return workDate; }set { workDate = value; }}private string company;public string Company{get { return company; }set { company = value; }}public Object Clone(){return (Object)this.MemberwiseClone(); // 深复制}}}
下一篇:Radius协议讲解