亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

(第Ⅱ部分 創建型模式篇)第5章 原型模式(Proty

系統 2029 0

 ——.NET設計模式系列之六  

 Terrylee  ,  2006  年  1  月  

 概述        

 在軟件系統中,有時候面臨的產品類是動態變化的,而且這個產品類具有一定的等級結構。這時如果用工廠模式,則與產品類等級結構平行的工廠方法類也要隨著這種變化而變化,顯然不大合適。那么如何封裝這種動態的變化?從而使依賴于這些易變對象的客戶程序不隨著產品類變化?  

 意圖        

 用原型實例指定創建對象的種類,并且通過拷貝這些原型創建新的對象。  

 結構圖        

 張軍博客    

 Prototype  模式結構圖  

 生活中的例子        

 Prototype  模式使用原型實例指定創建對象的種類。新產品的原型通常是先于全部產品建立的,這樣的原型是被動的,并不參與復制它自己。一個細胞的有絲分裂,產生兩個同樣的細胞,是一個扮演主動角色復制自己原型的例子,這演示了原型模式。一個細胞分裂,產生兩個同樣基因型的細胞。換句話說,細胞克隆了自己。  

 張軍博客    

 使用細胞分裂例子的  Prototype  模式對象圖  

 原型模式解說        

 我們考慮這樣一個場景,假定我們要開發一個調色板,用戶單擊調色板上任一個方塊,將會返回一個對應的顏色的實例,下面我們看看如何通過原型模式來達到系統動態加載具體產品的目的。  

 很自然,我們利用  OO  的思想,把每一種顏色作為一個對象,并為他們抽象出一個公用的父類,如下圖:  

 張軍博客    

 實現代碼:  

 public  abstract        class         Color  

 {  

 public        abstract        void         Display();  

 }  

 public  class         RedColor:Color  

 {  

 public        override        void         Display()  

  {  

  Console      .        WriteLine(      "Red's RGB Values are:255,0,0"        );  

  }  

 }  

 public  class         GreenColor:Color  

 {  

 public        override        void         Display()  

  {  

  Console      .        WriteLine(      "Green's RGB Values are:0,255,0"        );  

  }  

 }  

 客戶程序需要某一種顏色的時候,只需要創建對應的具體類的實例就可以了。但是這樣我們并沒有達到封裝變化點的目的,也許你會說,可以使用工廠方法模式,為每一個具體子類定義一個與其等級平行的工廠類,那么好,看一下實現:  

 張軍博客    
 實現代碼:
 

 public  abstract        class         ColorFactory  

 {  

 public        abstract         Color Create();  

 }  

 public  class         RedFactory:ColorFactory  

 {  

 public        override         Color Create()  

  {  

 return        new         RedColor();  

  }  

 }  

 public  class         GreenFactory:ColorFactory  

 {  

 public        override         Color Create()  

  {  

 return        new         GreenColor();  

  }  

 }  

 實現了這一步之后,可以看到,客戶程序只要調用工廠方法就可以了。似乎我們用工廠方法模式來解決是沒有問題的。但是,我們考慮的僅僅是封裝了  new  變化,而沒有考慮顏色的數量是不斷變化的,甚至可能是在程序運行的過程中動態增加和減少的,那么用這種方法實現,隨著顏色數量的不斷增加,子類的數量會迅速膨大,導致子類過多,顯然用工廠方法模式有些不大合適。  

 進一步思考,這些  Color  子類僅僅在初始化的顏色對象類別上有所不同。添加一個  ColorTool  這樣的類,來參數化的它的實例,而這些實例是由  Color  支持和創建的。我們讓  ColorTool  通過克隆或者拷貝一個  Color  子類的實例來創建新的  Color  ,這個實例就是一個原型。如下圖所示:  

 張軍博客    

 實現代碼:  

 abstract  class         ColorPrototype  

 {  

 public        abstract         ColorPrototype Clone();  

 }  

 class   ConcteteColorPrototype : ColorPrototype  

 {  

 private        int         _red, _green, _blue;  

 public         ConcteteColorPrototype(      int         red,      int         green,      int         blue)  

  {  

 this        .        _red      =         red;  

 this        .        _green      =         green;  

 this        .        _blue      =         blue;  

  }  

 public        override         ColorPrototype Clone()  

  {  

 //        實現淺拷貝  

 return         (ColorPrototype)      this        .        MemberwiseClone();  

  }  

 public        void         Display(      string         _colorname)  

  {  

  Console      .        WriteLine(      "{0}'s RGB Values are: {1},{2},{3}"        ,  

  _colorname,_red, _green, _blue );  

  }  

 }  

 class   ColorManager  

 {  

  Hashtable colors      =        new         Hashtable();  

 public         ColorPrototype      this        [      string         name]  

  {  

 get        

  {  

 return         (ColorPrototype)colors[name];  

  }  

 set        

  {  

  colors      .        Add(name,      value        );  

  }  

  }  

 }  

 現在我們分析一下,這樣帶來了什么好處?首先從子類的數目上大大減少了,不需要再為每一種具體的顏色產品而定一個類和與它等級平行的工廠方法類,而  ColorTool  則扮演了原型管理器的角色。再看一下為客戶程序的實現:  

 class   App  

 {  

 public        static        void         Main(      string        [] args)  

  {  

  ColorManager colormanager      =        new         ColorManager();  

 //        初始化顏色  

  colormanager[      "red"        ]      =        new         ConcteteColorPrototype(      255        ,      0        ,      0        );  

  colormanager[      "green"        ]      =        new         ConcteteColorPrototype(      0        ,      255        ,      0        );  

  colormanager[      "blue"        ]      =        new         ConcteteColorPrototype(      0        ,      0        ,      255        );  

  colormanager[      "angry"        ]      =        new         ConcteteColorPrototype(      255        ,      54        ,      0        );  

  colormanager[      "peace"        ]      =        new         ConcteteColorPrototype(      128        ,      211        ,      128        );  

  colormanager[      "flame"        ]      =        new         ConcteteColorPrototype(      211        ,      34        ,      20        );  

 //        使用顏色  

 string         colorName      =        "red"        ;  

  ConcteteColorPrototype c1      =         (ConcteteColorPrototype)colormanager[colorName]      .        Clone();  

  c1      .        Display(colorName);  

  colorName      =        "peace"        ;  

  ConcteteColorPrototype c2      =         (ConcteteColorPrototype)colormanager[colorName]      .        Clone();  

  c2      .        Display(colorName);  

  colorName      =        "flame"        ;  

  ConcteteColorPrototype c3      =         (ConcteteColorPrototype)colormanager[colorName]      .        Clone();  

  c3      .        Display(colorName);  

  Console      .        ReadLine();  

  }  

 }  

 可以看到,客戶程序通過注冊原型實例就可以將一個具體產品類并入到系統中,在運行時刻,可以動態的建立和刪除原型。  最后還要注意一點,在上面的例子中,用的是淺表復制。如果想做深復制,需要通過序列化的方式來實現。  經過了上面的分析之后,我們再來思考下面的問題:  

 1  .為什么需要Prototype模式?  

 引入原型模式的本質在于利用已有的一個原型對象,快速的生成和原型對象一樣的實例。你有一個A的實例a:A a      =  new A();        現在你想生成和car1一樣的一個實例b,按照原型模式,應該是這樣:A b      = a  .Clone();        而不是重新再new一個A對象。通過上面這句話就可以得到一個和a一樣的實例,確切的說,應該是它們的數據成員是一樣的。Prototype模式同樣是返回了一個A對象而沒有使用new操作。  

 2  .引入Prototype模式帶來了什么好處?  

 可以看到,引入Prototype模式后我們不再需要一個與具體產品等級結構平行的工廠方法類,減少了類的構造,同時客戶程序可以在運行時刻建立和刪除原型。  

 3  .Prototype模式滿足了哪些面向對象的設計原則?  

 依賴倒置原則:上面的例子,原型管理器(ColorManager)僅僅依賴于抽象部分(ColorPrototype),而具體實現細節(ConcteteColorPrototype)則依賴與抽象部分(ColorPrototype),所以Prototype很好的滿足了依賴倒置原則。  

 張軍博客    

 通過序列化實現深拷貝        

 要實現深拷貝,可以通過序列化的方式。抽象類及具體類都必須標注為可序列化的      [Serializable]        ,上面的例子加上深拷貝之后的完整程序如下:  

 using   System;  

 using   System      .        Collections;  

 using   System      .        IO;  

 using   System      .        Runtime      .        Serialization;  

 using   System      .        Runtime      .        Serialization      .        Formatters      .        Binary;  

 [Serializable]  

 abstract  class         ColorPrototype  

 {  

 public        abstract         ColorPrototype Clone(      bool         Deep);  

 }  

 [Serializable]  

 class   ConcteteColorPrototype : ColorPrototype  

 {  

 private        int         _red, _green, _blue;  

 public         ConcteteColorPrototype(      int         red,      int         green,      int         blue)  

  {  

 this        .        _red      =         red;  

 this        .        _green      =         green;  

 this        .        _blue      =         blue;  

  }  

 public        override         ColorPrototype Clone(      bool         Deep)  

  {  

 if        (Deep)  

 return         CreateDeepCopy();  

 else        

 return         (ColorPrototype)      this        .        MemberwiseClone();  

  }  

 //        實現深拷貝  

 public         ColorPrototype CreateDeepCopy()  

  {  

  ColorPrototype colorPrototype;  

  MemoryStream memoryStream      =        new         MemoryStream();  

  BinaryFormatter formatter      =        new         BinaryFormatter();  

  formatter      .        Serialize(memoryStream,      this        );  

  memoryStream      .        Position      =        0        ;  

  colorPrototype      =         (ColorPrototype)formatter      .        Deserialize(memoryStream);  

 return         colorPrototype;  

  }  

 public         ConcteteColorPrototype Create(      int         red,      int         green,      int         blue)  

  {  

 return        new         ConcteteColorPrototype(red,green,blue);  

  }  

 public        void         Display(      string         _colorname)  

  {  

  Console      .        WriteLine(      "{0}'s RGB Values are: {1},{2},{3}"        ,  

  _colorname,_red, _green, _blue );  

  }  

 }  

 class   ColorManager  

 {  

  Hashtable colors      =        new         Hashtable();  

 public         ColorPrototype      this        [      string         name]  

  {  

 get        

  {  

 return         (ColorPrototype)colors[name];  

  }  

 set        

  {  

  colors      .        Add(name,      value        );  

  }  

  }  

 }  

 class   App  

 {  

 public        static        void         Main(      string        [] args)  

  {  

  ColorManager colormanager      =        new         ColorManager();  

 //        初始化顏色  

  colormanager[      "red"        ]      =        new         ConcteteColorPrototype(      255        ,      0        ,      0        );  

  colormanager[      "green"        ]      =        new         ConcteteColorPrototype(      0        ,      255        ,      0        );  

  colormanager[      "blue"        ]      =        new         ConcteteColorPrototype(      0        ,      0        ,      255        );  

  colormanager[      "angry"        ]      =        new         ConcteteColorPrototype(      255        ,      54        ,      0        );  

  colormanager[      "peace"        ]      =        new         ConcteteColorPrototype(      128        ,      211        ,      128        );  

  colormanager[      "flame"        ]      =        new         ConcteteColorPrototype(      211        ,      34        ,      20        );  

 //        使用顏色  

 string         colorName      =        "red"        ;  

  ConcteteColorPrototype c1      =         (ConcteteColorPrototype)colormanager[colorName]      .        Clone(      false        );  

  c1      .        Display(colorName);  

  colorName      =        "peace"        ;  

  ConcteteColorPrototype c2      =         (ConcteteColorPrototype)colormanager[colorName]      .        Clone(      true        );  

  c2      .        Display(colorName);  

  colorName      =        "flame"        ;  

  ConcteteColorPrototype c3      =         (ConcteteColorPrototype)colormanager[colorName]      .        Clone(      true        );  

  c3      .        Display(colorName);  

  Console      .        ReadLine();  

  }  

 }  

 實現要點        

 1  .使用原型管理器,體現在一個系統中原型數目不固定時,可以動態的創建和銷毀,如上面的舉的調色板的例子。  

 2  .實現克隆操作,在  .NET  中可以使用  Object  類的  MemberwiseClone()  方法來實現對象的淺表拷貝或通過序列化的方式來實現深拷貝。  

 3  .  Prototype  模式同樣用于隔離類對象的使用者和具體類型(易變類)之間的耦合關系,它同樣要求這些“易變類”擁有穩定的接口。  

 效果        

 1  .它對客戶隱藏了具體的產品類,因此減少了客戶知道的名字的數目。  

 2  .  Prototype  模式允許客戶只通過注冊原型實例就可以將一個具體產品類并入到系統中,客戶可以在運行時刻建立和刪除原型。  

 3  .減少了子類構造,  Prototype  模式是克隆一個原型而不是請求工廠方法創建一個,所以它不需要一個與具體產品類平行的  Creater  類層次。  

 4  .  Portotype  模式具有給一個應用軟件動態加載新功能的能力。由于Prototype的獨立性較高,可以很容易動態加載新功能而不影響老系統。  

 5  .  產品類不需要非得有任何事先確定的等級結構,因為  Prototype  模式適用于任何的等級結構  

 6  .Prototype模式的最主要缺點就是每一個類必須配備一個克隆方法。而且這個克隆方法需要對類的功能進行通盤考慮,這對全新的類來說不是很難,但對已有的類進行改造時,不一定是件容易的事。  

 適用性        

 在下列情況下,應當使用  Prototype  模式:  

 1  .當一個系統應該獨立于它的產品創建,構成和表示時;  

 2  .當要實例化的類是在運行時刻指定時,例如,通過動態裝載;  

 3  .為了避免創建一個與產品類層次平行的工廠類層次時;  

 4  .當一個類的實例只能有幾個不同狀態組合中的一種時。建立相應數目的原型并克隆它們可能比每次用合適的狀態手工實例化該類更方便一些。  

 總結        

 Prototype  模式同工廠模式,同樣對客戶隱藏了對象的創建工作,但是,與通過對一個類進行實例化來構造新對象不同的是,原型模式是通過拷貝一個現有對象生成新對象的,達到了“  隔離類對象的使用者和具體類型(易變類)之間的耦合關系”的目的。   


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 国产亚洲精品国产一区 | 99热国产这里只有精品99 | 老司机日日摸夜夜摸精品影院 | 色综合久久88中文字幕 | 中文字幕不卡在线观看 | 久草青草 | 九九热中文字幕 | 九九伦理| 天天干天天做 | 精品国产一区二区三区不卡在线 | 奇米影视777色 | 国产专区自拍 | 99久久99热精品免费观看国产 | 亚洲精品一区二区久久 | 免费亚洲视频在线观看 | 欧美金妇欧美乱妇xxxx | 人人爱天天做夜夜爽毛片 | 狠狠躁天天躁 | 免费不卡中文字幕在线 | 国产主播在线看 | 老司机精品视频个人在观看 | 一级特黄aaa大片在 一级特黄aaa大片在线观看 | 久久久噜久噜久久综合 | 中文字幕一区二区三区 精品 | 亚洲伊人色一综合网 | 99热这里只有精品99 | 日本自己的私人影院 | 999久久狠狠免费精品 | 日本人xx视频免费视频 | 国产欧美综合在线一区二区三区 | 亚洲一区二区久久 | 一级aa 毛片高清免费看 | 日韩人成免费网站大片 | 99综合在线 | 亚洲精品tv久久久久久久久 | a一级毛片视频免费看 | 国产欧美成人 | 经典邵氏三级 在线观看 | 日本特级全黄一级毛片 | 久久伊人一区二区三区四区 | 免费观看一级欧美在线视频 |