設計模式之原型

原型模式介紹

完整拷貝

原型模式主要解決的問題就是創建重複對象,而這部分對象內容本身比較複雜,生成過程可能從庫或者RPC介面中獲取數據的耗時較長,因此採用克隆的方式節省時間。

原型模式是一種創建型設計模式,使你能夠複製已有對象,而無需使程式碼依賴它們所屬的類。

原型模式的特點

  • 在原型模式中所需要非常重要的手段就是克隆。
  • 原型模式的使用頻率不是很高。
  • 在一個很複雜的類層次中,當系統必須從其中的許多類型創建新對象時,可以考慮用原型。

便於通過克隆方式創造複雜對象,也可以避免重複做初始化操作,不需要與類中所屬的其他類耦合。

優點:

  • 向客戶隱藏製造新實例的複雜性
  • 提供讓客戶能夠產生未知類型對象的選項
  • 在某些環境下,複製對象比創建新對象更有效
  • 可以用繼承以外的方式來處理複雜對象的不同配置

缺點:

  • 對象的複製有時候很複雜

原型模式的結構

1、原型(Prototype)介面將對克隆進行聲明。在絕大數情況下,其中只會有一個名為clone的方法。

2、具體原型(Concrete Prototype)類將實現克隆方法。除了將原始對象的數據複製到克隆體中之外,該方法有時還需處理克隆過程中的極端情況,例如克隆關聯對象和梳理遞歸依賴等等。

3、客戶端(Client)可以複製實現了原型介面的任何對象。

所有的原型類都必須有一個通用的介面,使得即使在對象所屬的具體類未知的情況下也能複製對象。原型對象可以生產自身的完整副本,因為相同類的對象可以相互訪問對方的私有成員變數。

Demo

下面就以學生資訊為例來簡單學習下原型模式。入校時填寫學生資訊都是重複且簡單的工作,如果我們把格式規定好,其餘的學生按照一定的格式來編寫,那麼就可以使用原型模式。

    public class Student
    {
        public int Age;
        public DateTime BirthDate;
        public string Name;
        public IdInfo IdInfo;

        /// <summary>
        /// 淺拷貝
        /// </summary>
        /// <returns></returns>
        public Student ShallowCopy() 
        {
            return (Student)this.MemberwiseClone();
        }

        /// <summary>
        /// 深拷貝
        /// </summary>
        /// <returns></returns>
        public Student DeepCopy()
        {
            Student clone = (Student)this.MemberwiseClone();
            clone.IdInfo = new IdInfo(IdInfo.IdNumber);
            clone.Name = String.Copy(Name);
            return clone;
        }
    }
    public class IdInfo 
    {
        public int IdNumber;
        public IdInfo(int id)
        {
            IdNumber = id;
        }    
    }
        static void Main(string[] args)
        {
            Student student=new Student();
            student.Name = "阿輝";
            student.BirthDate = Convert.ToDateTime("1990-10-08");
            student.Age = 27;
            student.IdInfo = new IdInfo(001);

            Student studentTwo = student.ShallowCopy();
            var studentThree = student.DeepCopy();

            Console.WriteLine("學生資訊");
            Console.WriteLine("One");
            DisplayValues(student);
            Console.WriteLine("Two");
            DisplayValues(studentTwo);
            Console.WriteLine("Three");
            DisplayValues(studentThree);
            Console.WriteLine("--------------------------");


            student.Name = "阿七";
            student.Age = 18;
            student.BirthDate = Convert.ToDateTime("2018-10-08");
            student.IdInfo.IdNumber = 002;
            Console.WriteLine("修改後學生資訊");
            Console.WriteLine("One");
            DisplayValues(student);
            Console.WriteLine("Two");
            DisplayValues(studentTwo);
            Console.WriteLine("Three");
            DisplayValues(studentThree);
            Console.ReadKey();
        }

        public static void DisplayValues(Student s)
        {
            Console.WriteLine("      Name: {0:s}, Age: {1:d}, BirthDate: {2:MM/dd/yy}",
                s.Name, s.Age, s.BirthDate);
            Console.WriteLine("      ID: {0:d}", s.IdInfo.IdNumber);
        }

輸出結果

解釋:

可以看到在第一次創建學生對象的時候淺拷貝和深拷貝的值都是一樣的,和原始值一樣。

當我們修改學生資訊時,學生阿輝被修改為阿七,其餘屬性也被覆蓋進行修改。此時看淺拷貝和深拷貝的數據,發現在淺拷貝的時候只有ID值被修改,其餘值還和原數據一樣,在深拷貝中輸出的所有數據都和原始值一樣,也就是說修改的數據,根本沒有對深拷貝的數據進行覆蓋,深拷貝是對原始值的複製。

所有的原型類都必須有一個通用的介面,使得即使在對象所屬的具體類未知的情況下也能複製對象。原型對象可以生成自身的完整副本,因為相同類的對象可以相互訪問對方的私有成員變數。

對於上面這句話,你品,你細品

雖然說原型模式使用的頻次不是很多,但是我們需要大概知道如何使用,為什麼使用。

小寄語

人生短暫,我不想去追求自己看不見的,我只想抓住我能看的見的。

我是阿輝,感謝您的閱讀,如果對你有幫助,麻煩點贊、轉發 謝謝。