修飾模式

修飾模式，是面向物件程式領域中，一種動態地往一個類別中新增新的行為的設計模式。就功能而言，修飾模式相比生成子類別更為靈活，這樣可以給某個物件而不是整個類別新增一些功能。介紹.透過使用修飾模式，可以在執行時擴充一個類別的功能。原理是：增加一個修飾類包裹原來的類別，包裹的方式是在修飾類的建構函式中將原來的類以引數的形式傳入。裝飾類實現新的功能，但是，在不需要用到新功能的地方，它可以直接呼叫原來的類別中的方法。修飾類必須和原來的類別有相同的介面。修飾模式是類別繼承的另外一種選擇。類繼承在編譯時候增加行為，而裝飾模式是在執行時增加行為。當有幾個相互獨立的功能需要擴充時，這個區別就變得很重要。在有些面向物件的程式語言中，類別不能在執行時被建立，通常在設計的時候也不能預測到有哪幾種功能組合。這就意味著要為每一種組合建立一個新類別。相反，修飾模式是面向執行時候的物件例項的,這樣就可以在執行時根據需要進行組合。一個修飾模式的示例是JAVA裡的Java I/O Streams的實現。動機.舉個例子來說，在一個視窗軟體系統中呈現的一個視窗，為了讓視窗中呈現的內容資料能夠捲動，我們希望給它新增水平或垂直捲軸。假設視窗透過“Window”類例項來表示，並且假設它沒有新增捲軸功能。我們可以建立一個子類“ScrollingWindow”來提供，或者我們可以建立一個"ScrollingWindowDecorator"來為已存在的"Window"物件新增這個功能。在這點上，只要是解決方案就可以了。現在我們假設希望選擇給我們的視窗新增邊框，同樣，我們的原始"Window"類不支援。"ScrollingWindow"子類現在會造成一個問題，因為它會有效的建立一種新的視窗。如果我們想要給所有視窗新增邊框，我們必須建立"WindowWithBorder"和"ScrollingWindowWithBorder"子類。顯然，這個問題由於被新增類而變得更糟了。對於修飾模式，我們簡單的建立一個新類"BorderedWindowDecorator"，在執行時，我們能夠使用"ScrollingWindowDecorator"或"BorderedWindowDecorator"或兩者結合來修飾已存在的視窗。一個修飾能夠被應用的另一個好例子是當有需要根據某套規則或者幾個平行的規則集限制訪問物件的屬性或方法時。一個物件的屬性或方法按照某組規則或幾個並行規則(不同使用者證書等)需要限制訪問時，在這種情況下，不是在原始物件中實現訪問控制而是在他的使用中不變或不知道任何限制，並且他被包裝在一個訪問控制修飾物件中，這個物件能夠對允許的原始物件的介面子集服務。應用.Java IO 流為典型的裝飾模式。程式碼示例.Java.這個JAVA示例使用window/scrolling情境。// The Window interface classpublic interface Window {public void draw(); // Draws the Windowpublic String getDescription(); // Returns a description of the Window// implementation of a simple Window without any scrollbarspublic class SimpleWindow implements Window {public void draw() {// Draw windowpublic String getDescription() {return "simple window";以下類包含所有Window類的decorator，以及修飾類本身。// abstract decorator class - note that it implements Windowpublic abstract class WindowDecorator implements Window {protected Window decoratedWindow; // the Window being decoratedpublic WindowDecorator (Window decoratedWindow) {this.decoratedWindow = decoratedWindow;@Overridepublic void draw() {decoratedWindow.draw();@Overridepublic String getDescription() {return decoratedWindow.getDescription();// The first concrete decorator which adds vertical scrollbar functionalitypublic class VerticalScrollBar extends WindowDecorator {public VerticalScrollBar(Window windowToBeDecorated) {super(windowToBeDecorated);@Overridepublic void draw() {super.draw();drawVerticalScrollBar();private void drawVerticalScrollBar() {// Draw the vertical scrollbar@Overridepublic String getDescription() {return super.getDescription() + ", including vertical scrollbars";// The second concrete decorator which adds horizontal scrollbar functionalitypublic class HorizontalScrollBar extends WindowDecorator {public HorizontalScrollBar (Window windowToBeDecorated) {super(windowToBeDecorated);@Overridepublic void draw() {super.draw();drawHorizontalScrollBar();private void drawHorizontalScrollBar() {// Draw the horizontal scrollbar@Overridepublic String getDescription() {return super.getDescription() + ", including horizontal scrollbars";以下是一個測試程式，它建立了一個包含多重灌飾的Window例項(如,包含了垂直的和水平的捲軸),然後輸出它的描述：public class Main {// for print descriptions of the window subclassesstatic void printInfo(Window w) {System.out.println("description:"+w.getDescription());public static void main(String[] args) {// original SimpleWindowSimpleWindow sw = new SimpleWindow();printInfo(sw);// HorizontalScrollBar mixed WindowHorizontalScrollBar hbw = new HorizontalScrollBar(sw);printInfo(hbw);// VerticalScrollBar mixed WindowVerticalScrollBar vbw = new VerticalScrollBar(hbw);printInfo(vbw);以下是SimpleWindow及添加了元件HorizontalScrollBar和VerticalScrollBar後的Window測試結果：description:simple windowdescription:simple window, including horizontal scrollbarsdescription:simple window, including horizontal scrollbars, including vertical scrollbarsC++.C++程式碼示例:using namespace std;/* Component (interface) */class Widget {public:virtual void draw() = 0;/* ConcreteComponent */class TextField : public Widget {private:int width, height;public:TextField( int w, int h ){width = w;height = h;void draw() {cout « "TextField: " « width « ", " « height « '\n';};/* Decorator (interface) */class Decorator : public Widget {private:Widget* wid; // reference to Widgetpublic:Decorator( Widget* w ) {wid = w;void draw() {wid-&gt;draw();~Decorator() {delete wid;};/* ConcreteDecoratorA */class BorderDecorator : public Decorator {public:void draw() {Decorator::draw();cout « " BorderDecorator" « '\n';};/* ConcreteDecoratorB */class ScrollDecorator : public Decorator {public:void draw() {Decorator::draw();cout « " ScrollDecorator" « '\n';};int main( void ) {Widget* aWidget = new BorderDecorator(new BorderDecorator(new ScrollDecorator(new TextField( 80, 24 ))));aWidget-&gt;draw();delete aWidget;C#.C#程式碼示例:namespace GSL_Decorator_patterninterface IWindowObjectvoid Draw(); // draws the objectstring GetDescription(); // returns a description of the objectclass ControlComponent : IWindowObjectpublic ControlComponent()public void Draw() // draws the objectConsole.WriteLine( "ControlComponent::draw()" );public string GetDescription() // returns a description of the objectreturn "ControlComponent::getDescription()";abstract class Decorator : IWindowObjectprotected IWindowObject _decoratedWindow = null; // the object being decoratedpublic Decorator( IWindowObject decoratedWindow)_decoratedWindow = decoratedWindow;public virtual void Draw()_decoratedWindow.Draw();Console.WriteLine("\tDecorator::draw() ");public virtual string GetDescription() // returns a description of the objectreturn _decoratedWindow.GetDescription() + "\n\t" + "Decorator::getDescription() ";// the first decoratorclass DecorationA : Decoratorpublic DecorationA(IWindowObject decoratedWindow) : base(decoratedWindow)public override void Draw()base.Draw();DecorationAStuff();private void DecorationAStuff()Console.WriteLine("\t\tdoing DecorationA things");public override string GetDescription()return base.GetDescription() + "\n\t\tincluding " + this.ToString();}// end class ConcreteDecoratorA : Decoratorclass DecorationB : Decoratorpublic DecorationB(IWindowObject decoratedWindow) : base(decoratedWindow)public override void Draw()base.Draw();DecorationBStuff();private void DecorationBStuff()Console.WriteLine("\t\tdoing DecorationB things");public override string GetDescription()return base.GetDescription() + "\n\t\tincluding " + this.ToString();}// end class DecorationB : Decoratorclass DecorationC : Decoratorpublic DecorationC(IWindowObject decoratedWindow) : base(decoratedWindow)public override void Draw()base.Draw();DecorationCStuff();private void DecorationCStuff()Console.WriteLine("\t\tdoing DecorationC things");public override string GetDescription()return base.GetDescription() + "\n\t\tincluding " + this.ToString();}// end class DecorationC : Decorator}// end of namespace GSL_Decorator_patternpublic class MyClassGo.Go程式碼示例:package mainimport "fmt"// step1: 編寫基礎功能，剛開始不需要定義介面type Base struct {func (b *Base) Call() string {return "base is called"// step2: 將上面的方法宣告為介面型別，基礎功能中的 Call() 呼叫自動滿足下面的介面type DecoratorI interface {Call() string// step3: 編寫新增功能，結構中儲存介面型別的引數type Decorator struct {derorator DecoratorIfunc (d *Decorator) Call() string {return "decorator: " + d.derorator.Call()func main() {fmt.Println(base.Call())fmt.Println(decorator.Call())