原型模式(Prototype):用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式其实就是从一个对象再创建另一个可定制的对象,而且不需要知道任何创建的细节。
一般在初始化的信息不发生变化的情况下,克隆是最好的办法,这既隐藏了对象创建的细节,又对性能是很大的提升。
基本代码:
abstract class Prototype//原型类 { private string id; public Prototype(string id) { this.id = id; } public string Id { get { return id; } } public abstract Prototype Clone(); } class ConcretePrototype1:Prototype//具体原型类 { public ConcretePrototype1(string id):base(id) { } public override Prototype Clone() { return (Prototype)this.MemberwiseClone(); //创建当前对象的浅表副本。方法是创建一个新对象,然后将当前对象的非静态字段复制到该新对象。如果字段是值类型的,则对该字段执行逐位复制,如果字段是引用类型 //则复制引用但不复制引用的对象;因此原始对象及其副本引用同一对象【即引用的对象数据是不会被克隆过来的】 } }View Code
static void Main(string[] args) { //浅复制 ConcretePrototype1 p1 = new ConcretePrototype1("I"); ConcretePrototype1 C1=(ConcretePrototype1)p1.Clone(); Console.WriteLine("Cloned:{0}" ,C1.Id); Console.Read(); }View Code
注意以上MemberWiseClone()方法只是进行了浅拷贝,它只会复制引用但不会复制引用的对象,例如如下案例:就介绍了浅拷贝的特点。
客户端
static void Main(string[] args) { Resume a = new Resume("我是谁"); a.SetPersonalInfo("男", "29"); a.SetWorkExperience("2018-11-1", "杭州德川"); Resume b = (Resume)a.Clone(); b.SetWorkExperience("2020-2-09", "dahua"); Resume c = (Resume)a.Clone(); c.SetPersonalInfo("女", "23"); c.SetWorkExperience("2021-9-08", "kaba"); a.Display(); b.Display(); c.Display(); Console.Read(); }View Code
class WorkExperience { public string WorkData { get; set; } public string Company { get; set; } } class Resume : ICloneable { private string name; private string sex; private string age; private WorkExperience work; public Resume(string name) { this.name = name; this.work = new WorkExperience(); } public void SetPersonalInfo(string sex,string age) { this.sex = sex; this.age = age; } public void SetWorkExperience(string workData,string company) { work.Company = company; work.WorkData = workData; } public void Display() { Console.WriteLine("{0},{1},{2}", name, sex, age); Console.WriteLine("工作经历:{0},{1}", work.WorkData, work.Company); } public object Clone() { return (object)this.MemberwiseClone(); } }View Code
最后会发现输出的都是“工作经历 2021-9-08 kaba"。这就是浅拷贝,被复制的所有变量都含有与原来的对象相同的值,而所有的对其对象的引用都指向原来的值。
为了解决这个问题需要把复制的对象所引用的对象都复制一遍,这就是深拷贝。
代码修改如下:
class WorkExperience:ICloneable { public string WorkData { get; set; } public string Company { get; set; } public object Clone() { return (object)this.MemberwiseClone(); } } class Resume : ICloneable { private string name; private string sex; private string age; private WorkExperience work; public Resume(string name) { this.name = name; this.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 workData,string company) { work.Company = company; work.WorkData = workData; } public void Display() { Console.WriteLine("{0},{1},{2}", name, sex, age); Console.WriteLine("工作经历:{0},{1}", work.WorkData, 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; } }View Code