設計模式-結構型-裝飾者模式

  • 2019 年 10 月 3 日
  • 筆記

裝飾者模式(wrapper):

  允許向一個現有的對象添加新的功能,同時又不改變其結構。裝飾器模式是一種用於代替繼承的技術,無需通過繼承增加子類就能擴展對象的新功能。使用對象的關聯關係代替繼承關係,更加靈活,同時避免類型體系的快速膨脹。

示例:英雄學習技能 

  1 public class Program    2 {    3     private static void Main(string[] args)    4     {    5         //選擇英雄    6         Hero hero = new BlindMonk();    7         Skills skills = new Skills(hero);    8         Skills r = new Skill_R(skills, "猛龍擺尾");    9         Skills e = new Skill_E(r, "天雷破/摧筋斷骨");   10         Skills w = new Skill_W(e, "金鐘罩/鐵布衫");   11         Skills q = new Skill_Q(w, "天音波/迴音擊");   12         //學習技能   13         q.learnSkill();   14     }   15 }   16   17 /// <summary>   18 /// Component 英雄介面   19 /// </summary>   20 public interface Hero   21 {   22     void learnSkill();   23 }   24   25 /// <summary>   26 /// ConcreteComponent 具體英雄盲僧   27 /// </summary>   28 public class BlindMonk : Hero   29 {   30     public void learnSkill()   31     {   32         Console.WriteLine($"盲僧學習了以上技能!");   33     }   34 }   35   36 /// <summary>   37 /// Decorator 技能欄   38 /// </summary>   39 public class Skills : Hero   40 {   41     private Hero hero;   42   43     public Skills(Hero hero)   44     {   45         this.hero = hero;   46     }   47   48     public virtual void learnSkill()   49     {   50         if (hero != null)   51             hero.learnSkill();   52     }   53 }   54   55 /// <summary>   56 /// ConreteDecorator 技能:Q   57 /// </summary>   58 public class Skill_Q : Skills   59 {   60     private string _skillName;   61   62     public Skill_Q(Hero hero, string skillName) : base(hero)   63     {   64         this._skillName = skillName;   65     }   66   67     public override void learnSkill()   68     {   69         Console.WriteLine($"學習了技能Q:{this._skillName}");   70         base.learnSkill();   71     }   72 }   73   74 /// <summary>   75 /// ConreteDecorator 技能:W   76 /// </summary>   77 public class Skill_W : Skills   78 {   79     private string _skillName;   80   81     public Skill_W(Hero hero, string skillName) : base(hero)   82     {   83         this._skillName = skillName;   84     }   85   86     public override void learnSkill()   87     {   88         Console.WriteLine($"學習了技能W:{this._skillName}");   89         base.learnSkill();   90     }   91 }   92   93 /// <summary>   94 /// ConreteDecorator 技能:E   95 /// </summary>   96 public class Skill_E : Skills   97 {   98     private string _skillName;   99  100     public Skill_E(Hero hero, string skillName) : base(hero)  101     {  102         this._skillName = skillName;  103     }  104  105     public override void learnSkill()  106     {  107         Console.WriteLine($"學習了技能E:{this._skillName}");  108         base.learnSkill();  109     }  110 }  111  112 /// <summary>  113 /// ConreteDecorator 技能:R  114 /// </summary>  115 public class Skill_R : Skills  116 {  117     private string _skillName;  118  119     public Skill_R(Hero hero, string skillName) : base(hero)  120     {  121         this._skillName = skillName;  122     }  123  124     public override void learnSkill()  125     {  126         Console.WriteLine($"學習了技能R:{this._skillName}");  127         base.learnSkill();  128     }  129 }

裝飾者模式有四個角色:

   

  1)抽象構建(Component ):給出一個抽象介面,來規範被添加職責的對象;

  2)具體構件(ConcreteComponent):定義一個將要接收附加責任的具體對象;

  3)裝飾抽象類(Decorator):持有一個構件(Component)對象的實例,並定義一個與抽象構件介面一致的介面;

  4)具體裝飾對象(ConreteDecorator):負責給構件對象 ”貼上“附加的責任。起到給Component添加職責的功能。

要點: 

  1)裝飾者和被裝飾對象有相同的超類型。  

  2)可以用一個或多個裝飾者包裝一個對象。  

  3)裝飾者可以在所委託被裝飾者的行為之前或之後,加上自己的行為,以達到特定的目的。  

  4)對象可以在任何時候被裝飾,所以可以在運行時動態的,不限量的用你喜歡的裝飾者來裝飾對象。  

  5)裝飾模式中使用繼承的關鍵是想達到裝飾者和被裝飾對象的類型匹配,而不是獲得其行為。 

  6)裝飾者一般對組件的客戶是透明的,除非客戶程式依賴於組件的具體類型。在實際項目中可以根據需要為裝飾者添加新的行為,做到“半透明”裝飾者。

.NET中裝飾者的使用: 

MemoryStream memoryStream = new MemoryStream(new byte[] {95,96,97,98,99});   // 擴展緩衝的功能  BufferedStream buffStream = new BufferedStream(memoryStream);  // 添加加密的功能  CryptoStream cryptoStream = new CryptoStream(memoryStream,new AesManaged().CreateEncryptor(),CryptoStreamMode.Write);  // 添加壓縮功能  GZipStream gzipStream = new GZipStream(memoryStream, CompressionMode.Compress, true);  

裝飾者模式的優缺點:

  優點:1)裝飾這模式和繼承的目的都是擴展對象的功能,但裝飾者模式比繼承更靈活;

     2)通過使用不同的具體裝飾類以及這些類的排列組合,設計師可以創造出很多不同行為的組合;

      3)裝飾者模式有很好地可擴展性

  缺點:裝飾者模式會導致設計中出現許多小對象,如果過度使用,會讓程式變的更複雜。並且更多的對象會是的差錯變得困難,特別是這些對象看上去都很像。

裝飾者模式與代理模式的區別:

  1)兩種模式的關注點不同,裝飾者模式關注的是在一個對象上動態的添加方法,而代理模式關注的是控制對象的訪問。

  2)裝飾者模式可以讓使用者直觀的看到增強了哪些功能,而代理模式完全限制了使用者,只去調用代理,至於代理裡面增加了什麼功能,使用者是不知道,隱藏了一個對象的具體資訊,這正是為什麼代理模式在初始化時不能像裝飾模式一樣傳入一個原始對象的參數的原因。

  3)代理和真實對象之間的的關係通常在編譯時就已經確定了,而裝飾者能夠在運行時遞歸地被構造。

參考:https://www.cnblogs.com/jaredlam/archive/2011/11/08/2241089.html  

   https://www.cnblogs.com/zhili/p/DecoratorPattern.html

   https://blog.csdn.net/lxt610/article/details/81009089