原型模式——建立型模式

思路:

立刻又到找工做的时候了,当咱们在准备一份份简历的时候有没有考虑过这样一个问题?程序员

面对不一样的工做岗位咱们须要准备不一样的求职简历,可是这样的几份不一样的简历中仍是有至关大的部分是相同的,咱们若是每一份都从头开始从新制做,无疑是作了不少的无用功,浪费了不少时间。性能

那么,咱们有没有办法不用从新new一个简历,只是对某一个原件进行适当的修改,就能实现这个功能呢?this

别忘了,咱们是程序员呀,程序员别的不必定行,Ctrl+C和Ctrl+V仍是很溜的。复制下来对须要修改的部分进行修改不就好了?code

可是一样别忘了,咱们是程序员,若是这样一个问题用程序的思惟来看,又会是什么样呢?对象

咱们须要一个简历类,咱们能够设置我的信息、工做经历,而且把它们显示出来。咱们能够怎么写呢?接口

class Program
    {
        static void Main(string[] args)
        {
            Resume a;
            a = new Resume("张三");
            a.SetPersonalInfo("男", "22");
            a.SetWorkExperience("1998-2000", "XX公司");
            a.SetAimCompany("Google");

            Resume b =  new Resume("张三");
            b = a;
            a.Display();
            b.Display();

            b.SetAimCompany("IBM");
            a.Display();
            b.Display();
            Console.Read();
        }
    }

    class Resume  //简历
    {
        private string name;
        private string sex;
        private string age;
        private string timeArea;
        private string company;
        private string AimCompany;

        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 SetAimCompany(string AimCompany)
        {
            this.AimCompany = AimCompany;
        }

        //显示
        public void Display()
        {
            Console.WriteLine("尊敬的" + AimCompany + "公司领导,您好:");
            Console.WriteLine("{0} {1} {2}", name, sex, age);
            Console.WriteLine("工做经历:{0} {1}", timeArea, company);
            Console.WriteLine("");
        }
    }

那么由以上代码的运行结果咱们能够看到,当咱们改变b的工做经历的时候,a的工做经历一样改变了。这是什么缘由呢?由于内存

b=a;

这行代码执行的结果是,将a指向b的内容,并无给a分配内存空间。因此改变了b实际上改变了a指向的内容。即并无实现克隆的效果。原型

事实上,对于C#而言,由于克隆的经常使用,它在System命名空间里提供了ICloneable接口,其中一个唯一的方法就是Clone,咱们只须要实现这个接口就行了,而不用去写它的原型抽象类了。string

class Program
    {
        static void Main(string[] args)
        {
            Resume a = new Resume("张三");
            a.SetPersonalInfo("男", "22");
            a.SetWorkExperience("1998-2000", "XX公司");
            a.SetAimCompany("Google");

            Resume b = (Resume)a.Clone() ;
            a.Display();
            b.Display();

            b.SetAimCompany("IBM");
            a.Display();
            b.Display();
            Console.Read();
        }
    }

    //简历
    class Resume :  ICloneable
    {
        private string name;
        private string sex;
        private string age;
        private string timeArea;
        private string company;
        private string AimCompany;

        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 SetAimCompany(string AimCompany)
        {
            this.AimCompany = AimCompany;
        }


        //显示
        public void Display()
        {
            Console.WriteLine("尊敬的" + AimCompany + "公司领导,您好:");
            Console.WriteLine("{0} {1} {2}", name, sex, age);
            Console.WriteLine("工做经历:{0} {1}", timeArea, company);
            Console.WriteLine("");
        }

        public Object Clone()
        {
            return this.MemberwiseClone();//浅复制
        }

    }

有运行结果咱们能够看出,对b进行改变并不会改变a的结果,即实现了克隆的效果。产品

但须要注意的是,这里的克隆其实只是浅克隆。

值类型在克隆的时候是逐位复制,为深复制。而引用类型在复制时不复制引用的对象,只复制引用,为浅复制。而在C#中,string类型为特殊的引用类型,他能够被当作值类型进行深复制。因此在这里只是进行浅复制就能够达到效果。

可是一旦须要克隆类类型的变量的时候,不进行深复制是不行的。例如,咱们的简历类中有设置身份证的方法,而在实际中咱们通常会有一个身份证类,其间有身份证属性和设置身份证号的方法。这样就须要咱们提供一个对这些引用类型实现深复制的方法。

class Program
    {
        static void Main(string[] args)
        {
            Resume a = new Resume("张三");
            a.SetPersonalInfo("男", "22");
            a.SetWorkExperience("1998-2000", "XX公司");
            a.SetAimCompany("Google");

            Resume b = (Resume)a.DeepClone();
            a.Display();
            b.Display();

            b.SetAimCompany("IBM");
            b.idinfo.IdNumber = 56789;
            a.Display();
            b.Display();
            Console.Read();
        }
    }

    public class IDInfo
    {
        public int IdNumber;
        public IDInfo(int IdNumber)
        {
            this.IdNumber = IdNumber;
        }
    }

    //简历
    class Resume : ICloneable
    {
        private string name;
        private string sex;
        private string age;
        private string timeArea;
        private string company;
        private string AimCompany;
        public IDInfo idinfo;

        public Resume(string name)
        {
            this.name = name;
            idinfo = new IDInfo(123456);
        }

        //设置我的信息
        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 SetAimCompany(string AimCompany)
        {
            this.AimCompany = AimCompany;
        }


        //显示
        public void Display()
        {
            Console.WriteLine("尊敬的" + AimCompany + "公司领导,您好:");
            Console.WriteLine("{0} {1} {2}", name, sex, age);
            Console.WriteLine("工做经历:{0} {1}", timeArea, company);
            Console.WriteLine("ID号码:"+idinfo.IdNumber.ToString());
            Console.WriteLine("");
        }

        public Object Clone()
        {
            return this.MemberwiseClone();
        }

        public Object DeepClone()
        {
            Resume rsm = (Resume)this.MemberwiseClone();
            rsm.idinfo = new IDInfo(this.idinfo.IdNumber);
            return rsm;

        }

    }

以上,就是原型模式的思路和方法。

UML图:

吐槽:

原型模式就是从一个对象在建立另一个可定制的对象,并且不需知道任何建立的细节。

优势:

通常在初始化信息不发生变化的状况下,克隆是最好的办法,这既隐藏了对象建立的细节,又对性能是大大的提升。由于它不须要重新初始化对象,而是动态的得到对象运行时的状态。

原型模式容许动态增长或减小产品类。

原型模式具备给一个应用软件动态加载新功能的能力。

产品类不须要非得有任何事先肯定的等级结构 。

缺点:

每个类必须配备一个克隆方法。并且这个克隆方法须要对类的功能进行通盘考虑,这对全新的类来讲不是很难,但对已有的类进行改造时,不必定是件容易的事。

在实现深克隆时须要编写较为复杂的代码。

使用情景:

建立新对象成本较大(CPU,初始化)。

系统要保存对象的状态,对象状态变化很小。

当一个类的实例只有几个不一样状态组合时,创建相应数目的原型并克隆它们可能比每次用合适的状态手工实例化更为方便。

 

本菜鸟的疑难杂症:

一、在C#中类类型是引用类型,因此复制时默认浅复制。而string是一种特殊的引用类型,在处理的时候底层会把它当作值类型处理。

二、浅复制代表,被复制的对象的全部变量都含有与原来的对象相同的值,而全部的对其余对象的引用都仍然指向原来对象。要实现复制以后引用类型不指向同一个对象,就须要把复制的对象所引用的对象都复制一遍,即深复制。深复制把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。

相关文章
相关标签/搜索