Decorator定義:
動態給一個對象添加一些額外的職責,就象在墻上刷油漆.使用Decorator模式相比用生成子類方式達到功能的擴充顯得更為靈活.
為什么使用Decorator?
我們通??梢允褂美^承來實現功能的拓展,如果這些需要拓展的功能的種類很繁多,那么勢必生成很多子類,增加系統的復雜性,同時,使用繼承實現功能拓展,我們必須可預見這些拓展功能,這些功能是編譯時就確定了,是靜態的.
使用Decorator的理由是:這些功能需要由用戶動態決定加入的方式和時機.Decorator提供了"即插即用"的方法,在運行期間決定何時增加何種功能.
程序舉例:
Display.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));
}
}
}
Border .java:
public abstract class Border extends Display {
protected Display display; // 指裝飾外框里面的「內容」??
protected Border(Display display) { // 在產生對象實例時,以參數指定「內容」
this.display = display;
}
}
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;
}
}
}
SideBorder.java:
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;
}
}
UpDownBorder .java:
public class UpDownBorder extends Border {
private char borderChar; // 裝飾字符
public UpDownBorder(Display display, char ch) { // 以構造子指定Display和裝飾字符
super(display);
this.borderChar = ch;
}
public int getColumns() { // 字數同內容的字數
return display.getColumns();
}
public int getRows() { // 行數要再加上內容上下的裝飾字符的行數
return 1 + display.getRows() + 1;
}
public String getRowText(int row) { // 指定該行的內容
if (row == 0 || row == getRows() - 1) {
return makeLine(borderChar, 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();
}
}
Main.java:
public class Main {
public static void main(String[] args) {
Display b1 = new StringDisplay("Hello, world.");
Display b2 = new UpDownBorder(b1, '-');
Display b3 = new SideBorder(b2, '*');
b1.show();
b2.show();
b3.show();
Display b4 =
new FullBorder(
new UpDownBorder(
new SideBorder(
new UpDownBorder(
new SideBorder(
new StringDisplay("您好。"),
'*'
),
'='
),
'|'
),
'/'
)
);
b4.show();
}
}
注意:display繼承類中的getRowText方法
這個方法把所有的用法都繼集成到一起