原型模式——建立型模式

思路:

立刻又到找工做的時候了,當咱們在準備一份份簡歷的時候有沒有考慮過這樣一個問題?程序員

面對不一樣的工做崗位咱們須要準備不一樣的求職簡歷,可是這樣的幾份不一樣的簡歷中仍是有至關大的部分是相同的,咱們若是每一份都從頭開始從新制做,無疑是作了不少的無用功,浪費了不少時間。性能

那麼,咱們有沒有辦法不用從新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是一種特殊的引用類型,在處理的時候底層會把它當作值類型處理。

二、淺複製代表,被複制的對象的全部變量都含有與原來的對象相同的值,而全部的對其餘對象的引用都仍然指向原來對象。要實現複製以後引用類型不指向同一個對象,就須要把複製的對象所引用的對象都複製一遍,即深複製。深複製把引用對象的變量指向複製過的新對象,而不是原有的被引用的對象。

相關文章
相關標籤/搜索