代码改变世界

原型模式

2010-08-26 22:18  Clingingboy  阅读(339)  评论(0编辑  收藏  举报

     分浅拷贝和深拷贝,值得注意的地方是浅拷贝无法复制引用类型

实现方法

浅拷贝:通过调用MemberwiseClone方法

深拷贝:通过序列化来实现

来看下面接口

[Serializable()]
 public abstract class IPrototype <T> {
   public T Clone() {
       return (T) this.MemberwiseClone(); // Shallow copy
   }
   
   public T DeepCopy() { // Deep Copy
       MemoryStream stream = new MemoryStream();
       BinaryFormatter formatter = new BinaryFormatter();
       formatter.Serialize(stream, this);
       stream.Seek(0, SeekOrigin.Begin);
       T copy = (T) formatter.Deserialize(stream);
       stream.Close();
     return copy;
   }
 }

为了区分浅拷贝和深拷贝的区别,在对象中再定义一个引用类型,为了实现深拷贝,都需要加上Serializable元数据

[Serializable()]
 // Helper class used to create a second level data structure
 class DeeperData {
   public string Data {get; set;}
   
   public DeeperData(string s) {
     Data = s;
   }
   public override string ToString () {
     return Data;
   }
 }
 
  [Serializable()]
 class  Prototype : IPrototype <Prototype>  {
   
   // Content members
   public string Country {get; set;}
   public string Capital {get; set;}
   public DeeperData Language {get; set;}
   
   public Prototype (string country, string capital, string language) {
     Country = country;
     Capital = capital;
     Language = new DeeperData(language);
   }
 
   public override string ToString() {
     return Country+"\t\t"+Capital+"\t\t->"+Language;
   }
 }

客户端测试调用

class PrototypeClient : IPrototype <Prototype> {
       
    static void Report (string s, Prototype a, Prototype b) {
      Console.WriteLine("\n"+s);
      Console.WriteLine("Prototype "+a+"\nClone      "+b);
    }
  
    static void Main () {
       
      PrototypeManager manager = new PrototypeManager();
      Prototype  c2, c3;
 
      // Make a copy of Australia's data
      c2  =  manager.prototypes["Australia"].Clone();
      Report("Shallow cloning Australia\n===============", 
          manager.prototypes["Australia"], c2);
         
      // Change the capital of Australia to Sydney
      c2.Capital = "Sydney"; 
      Report("Altered Clone's shallow state, prototype unaffected", 
          manager.prototypes["Australia"], c2);
 
      // Change the language of Australia (deep data)
      c2.Language.Data = "Chinese";
      Report("Altering Clone deep state: prototype affected *****", 
              manager.prototypes["Australia"], c2);
 
      // Make a copy of Germany's data
      c3 = manager.prototypes["Germany"].DeepCopy();
      Report("Deep cloning Germany\n============",
              manager.prototypes["Germany"], c3);
      
      // Change the capital of Germany
      c3.Capital = "Munich"; 
      Report("Altering Clone shallow state, prototype unaffected", 
              manager.prototypes["Germany"], c3);
         
      // Change the language of Germany (deep data)
      c3.Language.Data = "Turkish"; 
      Report("Altering Clone deep state, prototype unaffected",
          manager.prototypes["Germany"], c3);
      Console.ReadKey();
    }
  }

测试结果

/* Output
 Shallow cloning Australia
 ===============
 Prototype Australia           Canberra                ->English
 Clone      Australia            Canberra                ->English
 
 Altered Clone's shallow state, prototype unaffected
 Prototype Australia           Canberra                ->English
 Clone      Australia            Sydney                   ->English
 
 Altering Clone deep state: prototype affected *****浅拷贝结果
 Prototype Australia           Canberra                ->Chinese
 Clone      Australia            Sydney                   ->Chinese
 
 Deep cloning Germany
 ============
 Prototype Germany             Berlin          ->German
 Clone      Germany              Berlin          ->German
 
 Altering Clone shallow state, prototype unaffected
 Prototype Germany             Berlin          ->German
 Clone      Germany              Munich          ->German
 
 Altering Clone deep state, prototype unaffected深拷贝结果
 Prototype Germany             Berlin          ->German
 Clone      Germany              Munich          ->Turkish
 */

该模式在维护对象状态的时候,或者重复使用该对象的时候特别有用.