天天看點

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

我假設看這篇文章的朋友對裝飾者模式都能有各自的、深入的了解。因為這篇文章是讨論裝飾者模式的性能問題。

首先回顧一下裝飾者模式誕生的本意是什麼,它的官方意思是:動态地給一個對象添加一些額外的職責。我們都知道給對象擴充功能是通過繼承來實作,但是繼承有它的不好之處,比如:子類與父類之間的耦合、子類的無限擴大等等。而裝飾者模式就是想利用動态的給需要擴充的對象添加功能。将需要擴充的動能獨立起來,作為一個個裝飾類,在需要的時候給對象穿上這個裝飾。

1:

<a href="http://blog.51cto.com/attachment/201107/171508616.png" target="_blank"></a>

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

2:

<a href="http://blog.51cto.com/attachment/201107/171520244.png" target="_blank"></a>

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

但是當我們帶着這張圖的原理去看代碼的時候,它的結構根本不是這樣的“幹淨”。是以說理論與實踐是分不開的。請看代碼:

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  

            Console.WriteLine("ConcreteDecoratorB進行了方法的裝飾");  

            Console.WriteLine("ConcreteDecoratorB進行了Message方法的動态添加");  

    public class ConcreteDecoratorC : Decorator  

            Console.WriteLine("ConcreteDecoratorC進行了方法的裝飾");  

            Console.WriteLine("ConcreteDecoratorC進行了Message方法的動态添加");  

裝飾者模式的基本代碼原型差不多就這樣子的。當我看到裝飾者模式是這樣的一個代碼結構的時候,其實說心裡話我難受。裡面不是帶着繼承嗎?為什麼要繼承,心理面不忍發了點牢騷。ConcreteConpontent是被裝飾者對象,首先我們要确定要擴充的對象是可以讓我們擴充的。其實我知道繼承是為了拿到要擴充對象的行為,并且标示所有的裝飾者是屬于一種類型的,在使用的時候就可以用基類來使用所有的裝飾者。如果沒有繼承顯然是不能用基類進行統一調用的,繼承還有一個作用就是為了拿到被裝飾者的行為,用它的為操作不同的執行個體,是夠聰明的。

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

namespace ConsoleApplication1  

        public virtual void message()  

    public abstract class Decorator  

        private ConcreteConpontent m_compontent;  

        protected Decorator decorator;  

        public void SetCompontent(ConcreteConpontent com, Decorator de)  

            decorator = de;  

            if (decorator != null)  

                decorator.Operation();  

            else 

                m_compontent.Operation();  

                decorator.message();  

                m_compontent.message();  

            base.Operation();  

            Console.WriteLine("ConcreteDecoratorA進行了方法的裝飾");  

        public override void message()  

            base.message();  

            Console.WriteLine("ConcreteDecoratorA進行了message方法的動态添加");  

            Console.WriteLine("ConcreteDecoratorB進行了message方法的動态添加");  

            Console.WriteLine("ConcreteDecoratorC進行了message方法的動态添加");  

如果我們這是想擴充一個簡單的小功能,讓我們繼承一個很大的對象是不是有點不劃算。隻是想用被裝飾者的行為,去操作裝飾者原型執行個體。我們可以犧牲一下代碼的備援來解決這個性能問題。書上對繼承的解釋是用來避免手動輸入被裝飾者的行為代碼。我覺得這點根本沒有說服力。其實裝飾者模式是想動态的給對象添加功能、行為、職責。在使用的時候還是想通過被裝飾者進行引用所有的裝飾者執行個體,這樣才是繼承最有效的說服力。不繼承我一樣可以有同樣的行為、一樣可以實作無限遞增的嵌套裝飾者執行個體。要想執行個體套執行個體,那麼他們必須來自同一個祖先,同樣是裝飾者,要想讓裝飾者套裝飾者,那麼在裝飾者的類中需要有一個對裝飾者類型的引用,但是每一個裝飾者不可能一樣。是以必須讓他們繼承同一個基類才行,後面再多的裝飾者隻要繼承同一個基類那麼就可以互相引用。

總結:在我們選擇使用裝飾者模式的時候,需要根據自己的使用情況進行适當修改。在沒有必要的情況下不需要繼承那麼大的一個對象。

 本文轉自 王清培 51CTO部落格,原文連結:http://blog.51cto.com/wangqingpei557/622150,如需轉載請自行聯系原作者

繼續閱讀