首页 > 代码库 > 【设计模式】原型模式

【设计模式】原型模式

魔术师手拿一张百元大钞,瞬间又变出两张。也像配钥匙一样,拿一把钥匙,老师傅就能做出另一个一模一样的。像这种复制我们并不陌生,类似于我们设计中的原型模式

本文将从以下几点浅谈原型模式:

概述 

结构图

浅复制

深复制

总结

概述

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节。

    复制过程,并不是做一个抽象类,去实例化它。而是只需通过实现一个含有Clone()方法的接口就可以去克隆,这就是.NETSystem命名空间中提供的ICloneable接口


结构图:

 

 但,仅仅了解到这里是不够的。复制还有浅复制和深复制。掌握了它才能更好的运用复制模式。


浅复制:


浅复制:被复制对象的所有变量都含有与原来的对象相同的值。而所有的其他对象的引用都仍指向原来的对象。

结构图

代码

 

// 此为 工作经历 类
classWorkExperience
         {
            private  string workDate;
            public string WorkDate
            {
                get {return workDate ;}
                set {workDate =value;}
            }
 
            private  string company;
            public string Company
            {
                get {return company ;}
                set {company =value ;}
            } 
        }
 
 
 //简历类 其中会引用“工作经历”对象
class Resume:ICloneable //实现接口ICloneable ,该接口的方法就是Clone
    {
        private string name;
        private string age;
        private string sex;
 
       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 voidSetWorkExperience(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 ();
        }
}
 
 
 
 //客户端调用代码
      static void Main(string[] args)
    {
       Resume a =new Resume("大鸟");
       a.SetPersonalInfo("男","29");
       a.SetWorkExperience("1998-2000","xx公司");
 
        Resume b=(Resume)a.Clone();
       b.SetWorkExperience("1992-2006","YY公司");
 
        Resume c=(Resume)a.Clone();
       c.SetWorkExperience("1998-2003","zz企业");
       c.SetPersonalInfo("男", "24");
 
       a.Display();
       b.Display();
       c.Display();
       Console .Read ();
      }

 

浅复制图示


    如图,简历复制之后,它的“引用工作经历”处,仍需要引用。也就是说,浅复制并没有复制所引用的对象。也就是说,不管简历被复制多少分,工作经历类只有一个,因此也就可以解释,为什么代码中给abc三处工作经历设置,但却同时看到三个引用都是最好一次设置。因为三个引用,本来就是对一个对象的操作。

 

那我们看深复制是怎样的呢?


深复制

深复制:把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。

代码结构图


代码

   

class WorkExperience:ICloneable
    {
   private string workDate;
           
  publicstring WorkDate
            {
                get {return workDate ;}
                set{workDate =value;}
            }
 
            private  string company;
           
   publicstring Company
            {
                get {return company ;}
                set {company =value ;}
            }
           
   publicObject Clone()
            {
                return(Object)this.MemberwiseClone();
            }
           
        }
    //简历
    class Resume:ICloneable
    {
privatestring name;
        private string age;
        private string sex;
 
        private WorkExperience work;
 
        public Resume (string name )
        {
            this .name=name;
            work=new WorkExperience ();
 
        }
 
        //提供Clone方法调用的私有构造函数,以便克隆“工作经历”的数据
        private Resume(WorkExperience work)
        {
            this.work =(WorkExperience)work.Clone();
 
        }
 
        //设置个人信息
        public void  SetPersonalInfo(string sex,string age)
        {
            this.sex =sex;
            this .age=age;
 
        }
        //设置个人工作经历
        public voidSetWorkExperience(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;
 
    }
    }
 

深复制图示

 

 

第一步,深复制让工作经历也实现克隆接口。复制工作经历。

第二步,把复制后的工作经历放到简历中。

第三步,此时将简历复制,并给这个简历对象的相关字段赋值,最终即返回一个深复制的简历对象。

我们从中可以看出,此时再第三步中,我们重新设置工作经历,也只会影响当前的一个。而不会影响到工作经历的原型。因此,当我们需要一变二二变三时,就要用到深复制。

 

 

总结 

原型模式通过ICloneable接口实现。复制值时若字段是值,深/浅复制都逐位复制。若字段是引用类型,浅复制只复制引用但不复制引用的对象。深复制,复制引用的对象。