修饰模式

修飾模式，是物件導向編程領域中，一種動態地往一個類中添加新的行為的設計模式。就功能而言，修飾模式相比生成子類更為靈活，這樣可以給某個對象而不是整個類添加一些功能。

介紹

通過使用修飾模式，可以在運行時擴充一個類的功能。原理是：增加一個修飾類包裹原來的類，包裹的方式一般是通過在將原來的對象作為修飾類的構造函數的參數。裝飾類實現新的功能，但是，在不需要用到新功能的地方，它可以直接調用原來的類中的方法。修飾類必須和原來的類有相同的接口。
修飾模式是類繼承的另外一種選擇。類繼承在編譯時候增加行為，而裝飾模式是在運行時增加行為。
當有幾個相互獨立的功能需要擴充時，這個區別就變得很重要。在有些物件導向的程式語言中，類不能在運行時被創建，通常在設計的時候也不能預測到有哪幾種功能組合。這就意味著要為每一種組合創建一個新類。相反，修飾模式是面向運行時候的對象實例的,這樣就可以在運行時根據需要進行組合。一個修飾模式的示例是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 Window
public String getDescription(); // Returns a description of the Window}// implementation of a simple Window without any scrollbarspublic class SimpleWindow implements Window {
public void draw() {
// Draw window
}

public String getDescription() {
return "simple window";
}}
以下類包含所有Window類的decorator，以及修飾類本身。
 1 // abstract decorator class - note that it implements Window 2 public abstract class WindowDecorator implements Window { 3     protected Window decoratedWindow; // the Window being decorated 4  5     public WindowDecorator (Window decoratedWindow) { 6         this.decoratedWindow = decoratedWindow; 7     } 8     
 9     @Override10     public void draw() {11         decoratedWindow.draw();12     }13 14     @Override15     public String getDescription() {16         return decoratedWindow.getDescription();17     }18 }19 20 21 // The first concrete decorator which adds vertical scrollbar functionality22 public class VerticalScrollBar extends WindowDecorator {23 public VerticalScrollBar(Window windowToBeDecorated) {24 super(windowToBeDecorated);25 }26 27 @Override28 public void draw() {29 super.draw();30 drawVerticalScrollBar();31 }32 33 private void drawVerticalScrollBar() {34 // Draw the vertical scrollbar35 }36 37 @Override38 public String getDescription() {39 return super.getDescription() + ", including vertical scrollbars";40 }41 }42 43 44 // The second concrete decorator which adds horizontal scrollbar functionality45 public class HorizontalScrollBar extends WindowDecorator1 {46 public HorizontalScrollBar (Window windowToBeDecorated) {47 super(windowToBeDecorated);48 }49 50 @Override51 public void draw() {52 super.draw();53 drawHorizontalScrollBar();54 }55 56 private void drawHorizontalScrollBar() {57 // Draw the horizontal scrollbar58 }59 60 @Override61 public String getDescription() {62 return super.getDescription() + ", including horizontal scrollbars";63 }64 }
以下是一個測試程序，它創建了一個包含多重裝飾的Window實例(如,包含了垂直的和水平的滾動條),然後輸出它的描述：
public class Main {
// for print descriptions of the window subclasses
static void printInfo(Window w) {
System.out.println("description:"+w.getDescription());
}
public static void main(String[] args) {
// original SimpleWindow
SimpleWindow sw = new SimpleWindow();
printInfo(sw);
// HorizontalScrollBar  mixed Window
HorizontalScrollBar hbw = new HorizontalScrollBar(sw);
printInfo(hbw);
// VerticalScrollBar mixed Window
VerticalScrollBar vbw = new VerticalScrollBar(hbw);
printInfo(vbw);
}}
以下是SimpleWindow及添加了組件HorizontalScrollBar和VerticalScrollBar後的Window測試結果：
description:simple window
description:simple window, including horizontal scrollbars
description:simple window, including horizontal scrollbars, including vertical scrollbars

C++

C++代碼示例:
#include <iostream>using namespace std;/* Component (interface) */class Widget {public: 
  virtual void draw() = 0; 
  virtual ~Widget() {}};  

/* 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 Widget
                                  
public:
   Decorator( Widget* w )  { 
     wid = w; 
   }

   void draw() { 
     wid->draw(); 
   }

   ~Decorator() {
     delete wid;
   }};/* ConcreteDecoratorA */class BorderDecorator : public Decorator { 

public:
   BorderDecorator( Widget* w ) : Decorator( w ) { }
   void draw() {
      Decorator::draw();    
      cout << "   BorderDecorator" << '\n'; 
   }  
};/* ConcreteDecoratorB */class ScrollDecorator : public Decorator { 
public:
   ScrollDecorator( Widget* w ) : Decorator( w ) { }
   void draw() {
      Decorator::draw(); 
      cout << "   ScrollDecorator" << '\n';
   }  
};int main( void ) {
   
   Widget* aWidget = new BorderDecorator(
                        new BorderDecorator(
                           new ScrollDecorator(
                              new TextField( 80, 24 ))));
   aWidget->draw();
   delete aWidget;}

C#

C#代碼示例:
namespace GSL_Decorator_pattern{
interface IWindowObject
{
void Draw(); // draws the object
string GetDescription(); // returns a description of the object
}

class ControlComponent : IWindowObject
{
public ControlComponent()
{
}

public void Draw() // draws the object
{
Console.WriteLine( "ControlComponent::draw()" ); 
}

public string GetDescription() // returns a description of the object
{
return "ControlComponent::getDescription()";
}
}

abstract class Decorator : IWindowObject
{
protected IWindowObject _decoratedWindow = null; // the object being decorated

public Decorator( IWindowObject decoratedWindow)
{
_decoratedWindow = decoratedWindow;
}

public virtual void Draw()
{
_decoratedWindow.Draw();
Console.WriteLine("\tDecorator::draw() ");
}

public virtual string GetDescription() // returns a description of the object
{
return _decoratedWindow.GetDescription() + "\n\t" + "Decorator::getDescription() ";
}
}

// the first decorator 
class DecorationA : Decorator
{
public 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 : Decorator

class DecorationB : Decorator
{
public 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 : Decorator

class DecorationC : Decorator
{
public 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 MyClass

Go

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 DecoratorI}func (d *Decorator) Call() string {
return "decorator: " + d.derorator.Call()}func main() {
base := &Base{}
fmt.Println(base.Call())

decorator := Decorator{base}
fmt.Println(decorator.Call())}