我假設看這篇文章的朋友對裝飾者模式都能有各自的、深刻的理解。由於這篇文章是討論裝飾者模式的性能問題。設計模式
在本人的「.NET簡談設計模式之(裝飾者模式)」一文中比較詳細的講解了裝飾者模式的通常應用,可是我老是感受裝飾者模式隱隱約約之中有點不完美。通過我昨天一成天的思考、推敲終於找到了它隱隱約約中的那點不完美是什麼,爲了行爲去繼承帶來的無辜的性能開銷。因此本人想把它寫出來,跟你們討論下裝飾者模式的性能該如何平衡。是用時間換空間仍是用空間換時間,這裏的時間就是咱們開發的效率時間。ide
首先回顧一下裝飾者模式誕生的本意是什麼,它的官方意思是:動態地給一個對象添加一些額外的職責。咱們都知道給對象擴展功能是經過繼承來實現,可是繼承有它的很差之處,好比:子類與父類之間的耦合、子類的無限擴大等等。而裝飾者模式就是想利用動態的給須要擴展的對象添加功能。將須要擴展的動能獨立起來,做爲一個個裝飾類,在須要的時候給對象穿上這個裝飾。性能
1:spa
這張類圖照這個樣子發展下去不得了,子類無限膨脹,後面需求誰都不知道。這是咱們通常擴展對象的正常方法,咱們來看一下裝飾者模式的原型。設計
2:對象
將須要擴展的功能獨立起來,當須要的時候動態的添加功能。我想這就是裝飾者名稱由來,將後期擴展的功能比喻成裝飾者,是很形象。blog
可是當咱們帶着這張圖的原理去看代碼的時候,它的結構根本不是這樣的「乾淨」。因此說理論與實踐是分不開的。請看代碼:繼承
- using System;
- using System.Collections.Generic;
- using System.Text;
- namespace ConsoleApplication2
- {
- public class ConcreteConpontent
- {
- public virtual void Operation()
- {
- Console.WriteLine("頂級待裝飾對象");
- }
- public virtual void Message()
- {
- Console.WriteLine("頂級對象消息");
- }
- }
- public abstract class Decorator : ConcreteConpontent
- {
- protected ConcreteConpontent m_compontent;
- public void SetCompontent(ConcreteConpontent com)
- {
- m_compontent = com;
- }
- }
- public class ConcreteDecoratorA : Decorator
- {
- public override void Operation()
- {
- m_compontent.Operation();
- Console.WriteLine("ConcreteDecoratorA進行了方法的動態添加");
- }
- public override void Message()
- {
- m_compontent.Message();
- Console.WriteLine("ConcreteDecoratorA進行了Message方法的動態添加");
- }
- }
- public class ConcreteDecoratorB : Decorator
- {
- public override void Operation()
- {
- m_compontent.Operation();
- Console.WriteLine("ConcreteDecoratorB進行了方法的裝飾");
- }
- public override void Message()
- {
- m_compontent.Message();
- Console.WriteLine("ConcreteDecoratorB進行了Message方法的動態添加");
- }
- }
- public class ConcreteDecoratorC : Decorator
- {
- public override void Operation()
- {
- m_compontent.Operation();
- Console.WriteLine("ConcreteDecoratorC進行了方法的裝飾");
- }
- public override void Message()
- {
- m_compontent.Message();
- Console.WriteLine("ConcreteDecoratorC進行了Message方法的動態添加");
- }
- }
- }
裝飾者模式的基本代碼原型差很少就這樣子的。當我看到裝飾者模式是這樣的一個代碼結構的時候,其實說內心話我難受。裏面不是帶着繼承嗎?爲何要繼承,心理面不忍發了點牢騷。ConcreteConpontent是被裝飾者對象,首先咱們要肯定要擴展的對象是可讓咱們擴展的。其實我知道繼承是爲了拿到要擴展對象的行爲,而且標示全部的裝飾者是屬於一種類型的,在使用的時候就能夠用基類來使用全部的裝飾者。若是沒有繼承顯然是不能用基類進行統一調用的,繼承還有一個做用就是爲了拿到被裝飾者的行爲,用它的爲操做不一樣的實例,是夠聰明的。開發
我假如我不須要用基類進行統一調用裝飾者,我是否就能夠不繼承自被裝飾者了;爲了可以實現裝飾者的無限遞增的裝飾,我對代碼進行了簡單的修改,請看代碼:get
- using System;
- namespace ConsoleApplication1
- {
- public class ConcreteConpontent
- {
- public virtual void Operation()
- {
- Console.WriteLine("頂級待裝飾對象");
- }
- public virtual void message()
- {
- Console.WriteLine("頂級對象消息");
- }
- }
- public abstract class Decorator
- {
- private ConcreteConpontent m_compontent;
- protected Decorator decorator;
- public void SetCompontent(ConcreteConpontent com, Decorator de)
- {
- m_compontent = com;
- decorator = de;
- }
- public void SetCompontent(ConcreteConpontent com)
- {
- m_compontent = com;
- }
- public virtual void Operation()
- {
- if (decorator != null)
- decorator.Operation();
- else
- m_compontent.Operation();
- }
- public virtual void message()
- {
- if (decorator != null)
- decorator.message();
- else
- m_compontent.message();
- }
- }
- public class ConcreteDecoratorA : Decorator
- {
- public override void Operation()
- {
- base.Operation();
- Console.WriteLine("ConcreteDecoratorA進行了方法的裝飾");
- }
- public override void message()
- {
- base.message();
- Console.WriteLine("ConcreteDecoratorA進行了message方法的動態添加");
- }
- }
- public class ConcreteDecoratorB : Decorator
- {
- public override void Operation()
- {
- base.Operation();
- Console.WriteLine("ConcreteDecoratorB進行了方法的裝飾");
- }
- public override void message()
- {
- base.message();
- Console.WriteLine("ConcreteDecoratorB進行了message方法的動態添加");
- }
- }
- public class ConcreteDecoratorC : Decorator
- {
- public override void Operation()
- {
- base.Operation();
- Console.WriteLine("ConcreteDecoratorC進行了方法的裝飾");
- }
- public override void message()
- {
- base.message();
- Console.WriteLine("ConcreteDecoratorC進行了message方法的動態添加");
- }
- }
- }
若是咱們這是想擴展一個簡單的小功能,讓咱們繼承一個很大的對象是否是有點不划算。只是想用被裝飾者的行爲,去操做裝飾者原型實例。咱們能夠犧牲一下代碼的冗餘來解決這個性能問題。書上對繼承的解釋是用來避免手動輸入被裝飾者的行爲代碼。我以爲這點根本沒有說服力。其實裝飾者模式是想動態的給對象添加功能、行爲、職責。在使用的時候仍是想經過被裝飾者進行引用全部的裝飾者實例,這樣纔是繼承最有效的說服力。不繼承我同樣能夠有一樣的行爲、同樣能夠實現無限遞增的嵌套裝飾者實例。要想實例套實例,那麼他們必須來自同一個祖先,一樣是裝飾者,要想讓裝飾者套裝飾者,那麼在裝飾者的類中須要有一個對裝飾者類型的引用,可是每個裝飾者不可能同樣。因此必須讓他們繼承同一個基類才行,後面再多的裝飾者只要繼承同一個基類那麼就能夠互相引用。
總結:在咱們選擇使用裝飾者模式的時候,須要根據本身的使用狀況進行適當修改。在沒有必要的狀況下不須要繼承那麼大的一個對象。