---
# System prepended metadata

title: 裝飾模式 Decorator
tags: [Structural Patterns]

---

---
tags: Structural Patterns
---

# 裝飾模式 Decorator

## 架構圖

![](https://i.imgur.com/nA7YnM6.png)


**Component 參與者**
新增功能的核心參與者。在蛋糕的比喻說明中，相當於裝飾前的海綿蛋糕。Component 只規定海綿蛋糕的介面。例如 Display 類別。

**ConcreteComponent 參與者**
實作 Component 介面的具體海綿蛋糕。例如 StringDisplay 類別。

**Decorator (裝飾者) 參與者**
具有跟 Component 參與者相同的介面，另外還有 Decorator 要修飾的 Component。這個參與者是 "早就知道" 自己要去修飾的對象。例如 Border 類別。

**ConcreteDecorator 參與者**
具體的 Decorator 參與者，例如 SiderBorder 和 FullBorder 類別。


## 範例

``` java

public abstract class Display {
    public abstract int getColumns();               // 取得橫向的字數
    public abstract int getRows();                  // 取得直向的行數
    public abstract String getRowText(int row);     // 取得第row個字串
    public final void show() {                      // 列印所有內容
        for (int i = 0; i < getRows(); i++) {
            System.out.println(getRowText(i));
        }
    }
}
public abstract class Border extends Display {
    protected Display display;          // 指裝飾外框裡面的內容，裝飾裡面也可能包含裝飾
    protected Border(Display display) { // 產生物件個體時，以引數指定 "內容"
        this.display = display;
    }
}


public class FullBorder extends Border {
    public FullBorder(Display display) {
        super(display);
    }
    public int getColumns() {                   // 字數＝內容字數＋內容兩邊的裝飾字元
        return 1 + display.getColumns() + 1;
    }
    public int getRows() {                      // 行數＝內容行數＋上下的裝飾字元
        return 1 + display.getRows() + 1;
    }
    public String getRowText(int row) {         // 指定該行的內容
        if (row == 0) {                                                 // 外框頂端
            return "+" + makeLine('-', display.getColumns()) + "+";
        } else if (row == display.getRows() + 1) {                      // 外框底部
            return "+" + makeLine('-', display.getColumns()) + "+";
        } else {                                                        // 其他部分
            return "|" + display.getRowText(row - 1) + "|";
        }
    }
    private String makeLine(char ch, int count) {         // 以字元ch，建立重複count次的連續字串
        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < count; i++) {
            buf.append(ch);
        }
        return buf.toString();
    }
}
public class SideBorder extends Border {
    private char borderChar;                        // 裝飾字元
    public SideBorder(Display display, char ch) {   // 以建構子指定Display和裝飾字元 
        super(display);
        this.borderChar = ch;
    }
    public int getColumns() {                       // 字數要再加上內容兩邊的裝飾字元
        return 1 + display.getColumns() + 1;
    }
    public int getRows() {                          // 行數同內容的行數
        return display.getRows();
    }
    public String getRowText(int row) {             // 指定該行的內容即為在內容之指定行的兩邊
						    // 加上裝飾字元

        return borderChar + display.getRowText(row) + borderChar;
    }
}

//在這裡應用了 Template Method Pattern
public class StringDisplay extends Display {
    private String string;                          // 列印的字串
    public StringDisplay(String string) {           // 以引數指定列印的字串
        this.string = string;
    }
    public int getColumns() {                       // 字數
        return string.getBytes().length;
    }
    public int getRows() {                          // 行數為1
        return 1;
    }
    public String getRowText(int row) {             // 僅在row為0時才傳回
        if (row == 0) {
            return string;
        } else {
            return null;
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Display b1 = new StringDisplay("Hello, world.");
        Display b2 = new SideBorder(b1, '#');
        Display b3 = new FullBorder(b2);
        b1.show();
        b2.show();
        b3.show();
        Display b4 = 
                    new SideBorder(
                        new FullBorder(
                            new FullBorder(
                                new SideBorder(
                                    new FullBorder(
                                        new StringDisplay("您好。")
                                    ),
                                    '*'
                                )
                            )
                        ),
                        '/'
                    );
        b4.show();
    }
}

```

## 寫法

宣告component的abstract ，再由abstract的decorator去繼承compoent

再由實作的decorator去自訂abstract decorator的fuc。
在上面範例中 是先宣告concretecomponent，再把這個變數傳入concretedecortator

就是把基本的功能丟進擴充的功能中。
人類扔進職位

new 職位decortator( new 人類() )

>[name=陳閔致]