設計模式(16)---原型模式

1、定義ide

原型模式:用原型實例指定建立對象的種類,而且經過拷貝這些原型建立新的對象。函數

解釋:有一個設計很是複雜的對象,若是須要獲得多個這樣對象的時候,能夠先建立一個原型對象,而後使用原型對象clone出新的對象,從而實現減小內存消耗和類實例複用的目的。性能

 

2、UML類圖及基本代碼this

基本代碼:spa

abstract class Prototype
    {
        private string id;
        public string ID
        {
            get { return id; }
        }

        public Prototype(string id)
        {
            this.id = id;
        }

        public abstract Prototype Clone();
    }

    class ConcretePrototype : Prototype
    {
        public ConcretePrototype(string id)
            : base(id)
        { }

        public override Prototype Clone()
        {
            return (Prototype)this.MemberwiseClone();
        }
    }

客戶端調用:設計

ConcretePrototype cp1 = new ConcretePrototype("a");
            ConcretePrototype cp2 = (ConcretePrototype)cp1.Clone();

 

3、具體實例code

編寫一個簡歷,包含姓名、性別、年齡、工做經歷等,而後複製多份進行顯示。對象

實例代碼及運行結果:blog

class Program
    {
        static void Main(string[] args)
        {
            Resume resume1 = new Resume("tom");
            resume1.SetPersonInfo("man", "17");
            resume1.SetWorkExperience("1980-1990", "xx company");

            Resume resume2 = (Resume)resume1.Clone();
            resume2.SetWorkExperience("1990-2000", "yy company");

            Resume resume3 = (Resume)resume1.Clone();
            resume3.SetPersonInfo("man", "19");

            resume1.Display();
            resume2.Display();
            resume3.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 SetPersonInfo(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("workexperience:{0} {1}", timeArea, company);
        }

        public object Clone()
        {
            return (object)this.MemberwiseClone();
        }
    }
View Code

 

實例延伸:接口

上述實例總MemberwiseClone()方法是:若是字段是值類型,則對該字段執行逐位複製,若是字段是引用類型,則複製引用,但不復制引用的對象。這稱之爲淺拷貝,被複制對象的全部變量都含有與原來對象相同的值,而全部的對其餘對象的引用都仍然指向原來的對象。接下來,將工做經歷單獨拿出來做爲一個類在簡歷類中引用。以下:

class Program
    {
        static void Main(string[] args)
        {
            Resume resume1 = new Resume("tom");
            resume1.SetPersonInfo("man", "17");
            resume1.SetWorkExperience("1980-1990", "xx company");

            Resume resume2 = (Resume)resume1.Clone();
            resume2.SetWorkExperience("1990-2000", "yy company");

            Resume resume3 = (Resume)resume1.Clone();
            resume1.SetWorkExperience("2000-2010", "zz company");

            resume1.Display();
            resume2.Display();
            resume3.Display();

            Console.Read();
        }
    }

    class WorkExperience
    {
        private string timeArea;
        public string TimeArea
        {
            get { return timeArea; }
            set { timeArea = value; }
        }

        private string company;
        public string Company
        {
            get { return company; }
            set { company = value; }
        }
    }

    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 SetPersonInfo(string sex, string age)
        {
            this.sex = sex;
            this.age = age;
        }

        public void SetWorkExperience(string timeArea, string company)
        {
            work.TimeArea = timeArea;
            work.Company = company;
        }

        public void Display()
        {
            Console.WriteLine("{0} {1} {2}", name, sex, age);
            Console.WriteLine("workexperience:{0} {1}", work.TimeArea, work.Company);
        }

        public object Clone()
        {
            return (object)this.MemberwiseClone();
        }
    }
View Code

結果以下:

分析:工做經歷是有3段,但運行結果只顯示一段。因而可知淺拷貝對於類中引用對象的複製並不成功。

 

4、概念講解

淺拷貝:當對象的字段值被拷貝時,字段引用的對象不會被拷貝。例如,若是一個對象有一個指向字符串的字段,而且咱們對該對象作了一個淺拷貝,那麼這兩個對象將引用同一個字符串。

深拷貝:對對象實例中字段引用的對象也進行拷貝,若是一個對象有一個指向字符串的字段,而且咱們對該對象進行了深拷貝的話,那麼咱們將建立一個對象和一個新的字符串,新的對象將引用新的字符串。

也就是說,執行深拷貝建立的新對象和原來對象不會共享任何東西,改變一個對象對另一個對象沒有任何影響,而執行淺拷貝建立的新對象與原來對象共享成員,改變一個對象,另一個對象的成員也會改變。

 

5、實例改進

一樣是上述的實例,對於有引用字段的,本例使用深拷貝,代碼以下:

class Program
    {
        static void Main(string[] args)
        {
            Resume resume1 = new Resume("tom");
            resume1.SetPersonInfo("man", "17");
            resume1.SetWorkExperience("1980-1990", "xx company");

            Resume resume2 = (Resume)resume1.Clone();
            resume2.SetWorkExperience("1990-2000", "yy company");

            Resume resume3 = (Resume)resume1.Clone();
            resume1.SetWorkExperience("2000-2010", "zz company");

            resume1.Display();
            resume2.Display();
            resume3.Display();

            Console.Read();
        }
    }

    class WorkExperience:ICloneable //實現ICloneable接口
    {
        private string timeArea;
        public string TimeArea
        {
            get { return timeArea; }
            set { timeArea = value; }
        }

        private string company;
        public string Company
        {
            get { return company; }
            set { company = value; }
        }

        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;
            work = new WorkExperience();
        }

        private Resume(WorkExperience work)
        {
            this.work = (WorkExperience)work.Clone();//提供Clone方法調用的私有構造函數,以便克隆工做經歷的數據
        }

        public void SetPersonInfo(string sex, string age)
        {
            this.sex = sex;
            this.age = age;
        }

        public void SetWorkExperience(string timeArea, string company)
        {
            work.TimeArea = timeArea;
            work.Company = company;
        }

        public void Display()
        {
            Console.WriteLine("{0} {1} {2}", name, sex, age);
            Console.WriteLine("workexperience:{0} {1}", work.TimeArea, 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

運行結果:

 

6、優缺點及適用場景

優勢:

1)原型模式向客戶隱藏了建立新實例的複製性

2)容許動態增長或者減小產品類。

缺點:

1)每一個類必須配備一個克隆方法

2)對於新建的類使用拷貝很容易,對於已有的類進行拷貝時,特別當一個類引用不支持串行化的間接對象或引用含有循環結構的時候。

 

適用場景:

原型模式是在內存二進制流的拷貝,比直接new一個對象性能好不少,特別是須要大量對象時,能夠考慮使用原型模式。

類實例化須要消耗很是多的資源時或者實例化須要複雜的數據準備訪問權限時。

相關文章
相關標籤/搜索