📢 本文由 gemini-2.5-flash 翻譯
Decorator Pattern 物件結構型模式
目的
動態地為一個物件新增一些額外的職責。就增加功能而言,Decorator 模式比產生子類別更具彈性。
結構

其中:
- Component 定義一個物件介面,可以動態地為這些物件新增職責。
- ConcreteComponent 定義一個物件,可以為這個物件新增一些職責。
- Decorator 維持一個指向 Component 物件的指標,並定義一個與 Component 介面一致的介面。
- ConcreteDecorator 向元件新增職責。
適用性
Decorator 模式適用於:
- 在不影響其他物件的情況下,以動態、透明的方式為單一物件新增職責。
- 處理那些可以撤銷的職責。
- 當無法採用產生子類別的方式進行擴充時,一種情況是,可能有大量獨立的擴展,為支援每一種組合將產生大量的子類別,使得子類別數目呈爆炸性增長。另一種情況可能是,由於類別定義被隱藏,或類別定義不能用於產生子類別。
範例 1
某間咖啡店在販售咖啡時,可以根據顧客的要求在其中加入各種配料,咖啡店會根據所加入的配料來計算費用。咖啡店所供應的咖啡及配料種類和價格如下表所示。

現採用裝飾器模式來實現計算費用的功能,得到如下類別圖。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
| import java.util.*;
abstract class Beverage { // 飲料
String description = "Unknown Beverage";
public String getDescription() { return description; }
public abstract int cost();
}
abstract class CondimentDecorator extends Beverage { // 配料
Beverage beverage;
}
class Espresso extends Beverage { // 濃縮咖啡
private final int ESPRESSO_PRICE = 25;
public Espresso() { description = "Espresso"; }
public int cost() { return ESPRESSO_PRICE; }
}
class DarkRoast extends Beverage { // 深度烘焙咖啡
private final int DARKROAST_PRICE = 20;
public DarkRoast() { description = "DarkRoast"; }
public int cost() { rcturn DARKROAST PRICE; }
}
class Mocha extends CondimentDecorator { // 摩卡
private final int MOCHA_PRICE = 10;
public Mocha (Beverage beverage) { this.beverage = beverage; }
public String getDescription() {
return beverage.getDescription() + ", Mocha";
}
public int cost() { return MOCHA_PRICE + beverage.cost(); }
}
class Whip extends CondimentDecorator { // 奶泡
private final int WHIP_PRICE = 8;
public Whip (Beverage beverage) { this.beverage = beverage; }
public String getDescription() {
return beverage.getDescription() + ", Whip";
}
public int cost() { return WHIP_PRICE + beverage.cost(); }
}
public class Coffee {
public static void main(String args[]) {
Beverage beverage = new DarkRoast();
beverage = new Mocha(beverage);
beverage = new Whip(beverage);
System.out.println(beverage.getDescription() +" NT$ "+ beverage.cost());
}
}
|
範例 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
| public class DecoratorPattern {
public static void main(String[] args) {
Person p = new Student("Mike");
p.Operation();
System.out.println("\n--------------------");
p = new DecoratorA(p);
p.Operation();
System.out.println("\n--------------------");
p = new DecoratorB(p);
p.Operation();
// No.2
Person p2 = new DecoratorB(new Student("Jane"));
}
}
abstract class Person{
protected String name;
public abstract void Operation();
}
class Student extends Person{
public Student(String name){
this.name = name;
}
@Override
public void Operation(){
System.out.print(name + " 學習");
}
}
abstract class Decorator extends Person{
protected Person person;
}
class DecoratorA extends Decorator{
public DecoratorA(Person person){
this.person = person;
}
@Override
public void Operation() {
person.Operation();
System.out.print(" 玩樂");
}
}
class DecoratorB extends Decorator{
public DecoratorB(Person person){
this.person = person;
}
@Override
public void Operation() {
person.Operation();
System.out.print(" 考試");
}
}
|