設計模式之原型

—阿輝發表於2021-08-03

原型模式介紹

完整拷貝

原型模式主要解決的問題就是建立重複物件,而這部分物件內容本身比較複雜,生成過程可能從庫或者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值被修改,其餘值還和原資料一樣,在深拷貝中輸出的所有資料都和原始值一樣,也就是說修改的資料,根本沒有對深拷貝的資料進行覆蓋,深拷貝是對原始值的複製。

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

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

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

小寄語

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

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

相關文章