.NET簡談設計模式之(裝飾者模式性能問題?)

我假設看這篇文章的朋友對裝飾者模式都能有各自的、深刻的理解。由於這篇文章是討論裝飾者模式的性能問題。設計模式

在本人的「.NET簡談設計模式之(裝飾者模式)」一文中比較詳細的講解了裝飾者模式的通常應用,可是我老是感受裝飾者模式隱隱約約之中有點不完美。通過我昨天一成天的思考、推敲終於找到了它隱隱約約中的那點不完美是什麼,爲了行爲去繼承帶來的無辜的性能開銷。因此本人想把它寫出來,跟你們討論下裝飾者模式的性能該如何平衡。是用時間換空間仍是用空間換時間,這裏的時間就是咱們開發的效率時間。ide

首先回顧一下裝飾者模式誕生的本意是什麼,它的官方意思是:動態地給一個對象添加一些額外的職責。咱們都知道給對象擴展功能是經過繼承來實現,可是繼承有它的很差之處,好比:子類與父類之間的耦合、子類的無限擴大等等。而裝飾者模式就是想利用動態的給須要擴展的對象添加功能。將須要擴展的動能獨立起來,做爲一個個裝飾類,在須要的時候給對象穿上這個裝飾。性能

1:spa

這張類圖照這個樣子發展下去不得了,子類無限膨脹,後面需求誰都不知道。這是咱們通常擴展對象的正常方法,咱們來看一下裝飾者模式的原型。設計

2:對象

將須要擴展的功能獨立起來,當須要的時候動態的添加功能。我想這就是裝飾者名稱由來,將後期擴展的功能比喻成裝飾者,是很形象。blog

可是當咱們帶着這張圖的原理去看代碼的時候,它的結構根本不是這樣的「乾淨」。因此說理論與實踐是分不開的。請看代碼:繼承

  
  
  
  
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Text;  
  4.  
  5. namespace ConsoleApplication2  
  6. {  
  7.     public class ConcreteConpontent  
  8.     {  
  9.         public virtual void Operation()  
  10.         {  
  11.             Console.WriteLine("頂級待裝飾對象");  
  12.         }  
  13.         public virtual void Message()  
  14.         {  
  15.             Console.WriteLine("頂級對象消息");  
  16.         }  
  17.     }  
  18.  
  19.     public abstract class Decorator : ConcreteConpontent  
  20.     {  
  21.         protected ConcreteConpontent m_compontent;  
  22.         public void SetCompontent(ConcreteConpontent com)  
  23.         {  
  24.             m_compontent = com;  
  25.         }  
  26.     }  
  27.     public class ConcreteDecoratorA : Decorator  
  28.     {  
  29.         public override void Operation()  
  30.         {  
  31.             m_compontent.Operation();  
  32.             Console.WriteLine("ConcreteDecoratorA進行了方法的動態添加");  
  33.         }  
  34.         public override void Message()  
  35.         {  
  36.             m_compontent.Message();  
  37.             Console.WriteLine("ConcreteDecoratorA進行了Message方法的動態添加");  
  38.         }  
  39.     }  
  40.     public class ConcreteDecoratorB : Decorator  
  41.     {  
  42.         public override void Operation()  
  43.         {  
  44.             m_compontent.Operation();  
  45.             Console.WriteLine("ConcreteDecoratorB進行了方法的裝飾");  
  46.         }  
  47.         public override void Message()  
  48.         {  
  49.             m_compontent.Message();  
  50.             Console.WriteLine("ConcreteDecoratorB進行了Message方法的動態添加");  
  51.         }  
  52.     }  
  53.     public class ConcreteDecoratorC : Decorator  
  54.     {  
  55.         public override void Operation()  
  56.         {  
  57.             m_compontent.Operation();  
  58.             Console.WriteLine("ConcreteDecoratorC進行了方法的裝飾");  
  59.         }  
  60.         public override void Message()  
  61.         {  
  62.             m_compontent.Message();  
  63.             Console.WriteLine("ConcreteDecoratorC進行了Message方法的動態添加");  
  64.         }  
  65.     }  

裝飾者模式的基本代碼原型差很少就這樣子的。當我看到裝飾者模式是這樣的一個代碼結構的時候,其實說內心話我難受。裏面不是帶着繼承嗎?爲何要繼承,心理面不忍發了點牢騷。ConcreteConpontent是被裝飾者對象,首先咱們要肯定要擴展的對象是可讓咱們擴展的。其實我知道繼承是爲了拿到要擴展對象的行爲,而且標示全部的裝飾者是屬於一種類型的,在使用的時候就能夠用基類來使用全部的裝飾者。若是沒有繼承顯然是不能用基類進行統一調用的,繼承還有一個做用就是爲了拿到被裝飾者的行爲,用它的爲操做不一樣的實例,是夠聰明的。開發

我假如我不須要用基類進行統一調用裝飾者,我是否就能夠不繼承自被裝飾者了;爲了可以實現裝飾者的無限遞增的裝飾,我對代碼進行了簡單的修改,請看代碼:get

  
  
  
  
  1. using System;  
  2.  
  3. namespace ConsoleApplication1  
  4. {  
  5.     public class ConcreteConpontent  
  6.     {  
  7.         public virtual void Operation()  
  8.         {  
  9.             Console.WriteLine("頂級待裝飾對象");  
  10.         }  
  11.         public virtual void message()  
  12.         {  
  13.             Console.WriteLine("頂級對象消息");  
  14.         }  
  15.     }  
  16.  
  17.     public abstract class Decorator  
  18.     {  
  19.         private ConcreteConpontent m_compontent;  
  20.         protected Decorator decorator;  
  21.         public void SetCompontent(ConcreteConpontent com, Decorator de)  
  22.         {  
  23.             m_compontent = com;  
  24.             decorator = de;  
  25.         }  
  26.         public void SetCompontent(ConcreteConpontent com)  
  27.         {  
  28.             m_compontent = com;  
  29.         }  
  30.         public virtual void Operation()  
  31.         {  
  32.             if (decorator != null)  
  33.                 decorator.Operation();  
  34.             else 
  35.                 m_compontent.Operation();  
  36.         }  
  37.         public virtual void message()  
  38.         {  
  39.             if (decorator != null)  
  40.                 decorator.message();  
  41.             else 
  42.                 m_compontent.message();  
  43.         }  
  44.     }  
  45.     public class ConcreteDecoratorA : Decorator  
  46.     {  
  47.         public override void Operation()  
  48.         {  
  49.             base.Operation();  
  50.             Console.WriteLine("ConcreteDecoratorA進行了方法的裝飾");  
  51.         }  
  52.         public override void message()  
  53.         {  
  54.             base.message();  
  55.             Console.WriteLine("ConcreteDecoratorA進行了message方法的動態添加");  
  56.         }  
  57.     }  
  58.  
  59.     public class ConcreteDecoratorB : Decorator  
  60.     {  
  61.         public override void Operation()  
  62.         {  
  63.             base.Operation();  
  64.             Console.WriteLine("ConcreteDecoratorB進行了方法的裝飾");  
  65.         }  
  66.         public override void message()  
  67.         {  
  68.             base.message();  
  69.             Console.WriteLine("ConcreteDecoratorB進行了message方法的動態添加");  
  70.         }  
  71.     }  
  72.     public class ConcreteDecoratorC : Decorator  
  73.     {  
  74.         public override void Operation()  
  75.         {  
  76.             base.Operation();  
  77.             Console.WriteLine("ConcreteDecoratorC進行了方法的裝飾");  
  78.         }  
  79.         public override void message()  
  80.         {  
  81.             base.message();  
  82.             Console.WriteLine("ConcreteDecoratorC進行了message方法的動態添加");  
  83.         }  
  84.     }  

若是咱們這是想擴展一個簡單的小功能,讓咱們繼承一個很大的對象是否是有點不划算。只是想用被裝飾者的行爲,去操做裝飾者原型實例。咱們能夠犧牲一下代碼的冗餘來解決這個性能問題。書上對繼承的解釋是用來避免手動輸入被裝飾者的行爲代碼。我以爲這點根本沒有說服力。其實裝飾者模式是想動態的給對象添加功能、行爲、職責。在使用的時候仍是想經過被裝飾者進行引用全部的裝飾者實例,這樣纔是繼承最有效的說服力。不繼承我同樣能夠有一樣的行爲、同樣能夠實現無限遞增的嵌套裝飾者實例。要想實例套實例,那麼他們必須來自同一個祖先,一樣是裝飾者,要想讓裝飾者套裝飾者,那麼在裝飾者的類中須要有一個對裝飾者類型的引用,可是每個裝飾者不可能同樣。因此必須讓他們繼承同一個基類才行,後面再多的裝飾者只要繼承同一個基類那麼就能夠互相引用。

總結:在咱們選擇使用裝飾者模式的時候,須要根據本身的使用狀況進行適當修改。在沒有必要的狀況下不須要繼承那麼大的一個對象。

相關文章
相關標籤/搜索