設計模式學習筆記 - 4
寫在前面
今日特餐:裝飾器模式 (Decorator)
先稍微複習上一篇筆記《設計模式學習筆記 - 3》的內容-觀察者模式:
觀察者模式定義務鍵之間的一對多依賴關係,當一個物件改變狀態時,依賴它的物件都會自動收到通知與更新。
我們以Youtube 訂閱、開啟小鈴鐺為例,認識了觀察者(Observer)與 Subject 之間運作的方式。
今天要學習的設計模式是裝飾器模式,以下正文:
Decorator 裝飾器模式
裝飾器模式(Decorator Pattern) 可以動態的為物件附加額外的職責,使用裝飾器來擴展功能比使用繼承更有彈性。
使用書上舉的例子來做介紹:
咖啡廳飲品有各式各樣的咖啡,但每個消費者的需求會有些微變化,例如:
- A需要一杯濃縮咖啡+兩份鮮奶
- B需要一杯家常咖啡+燕麥奶
因為咖啡(Component)的單價與材料(Decorator)的單價都個別不同,因此在設計上會參考上圖,讓每杯飲品都能順利的紀錄咖啡與材料的內容與單價。
針對上述例子,我們用程式碼來呈現,看看怎麼實做能夠符合此設計模式的概念:
a. 飲品的部分我們設定了一個超類別- Berverage;
沒有變化的飲品都是實做這個類別,包含是否要增加其他的添加物,以及此產品的價格。
飲品的超類別
1
2
3
4
5
6
7
8
Interface Berverage {
public function getDescription();
public function getCost();
}Expresso
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Expresso implements Berverage {
private $description = 'Expresso';
public function getDescription() {
return $this->description;
}
public function getCost() {
return 85;
}
}House Blend Coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class HouseBlend implements Berverage {
private $description = 'House Blend Coffee';
public function getDescription() {
return $this->description;
}
public function getCost() {
return 80;
}
}
b. 添加物(調味品)的部分我們以牛奶與燕麥奶為例,可以分別取得加一份牛奶及一份燕麥奶,飲品的總價格會是什麼,並且將內容物描述出來,
提供店員明確的知道客戶點餐的內容:
Condiment Decorator 調味品/材料
1
2
3
4
5
6
7
8
9
10
11
12
abstract class CondimentDecorator {
public function __construct(Berverage $berverage) {
$this->berverage = $berverage;
}
abstract public function getDescription();
abstract public function getCost();
}Milk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Milk extends CondimentDecorator {
/** @var Berverage */
private $berverage;
public function __construct(Berverage $berverage) {
$this->berverage = $berverage;
}
public function getDescription() {
return $this->berverage->getDescription() . ', Milk';
}
public function getCost() {
return $this->berverage->getCost() + 20;
}
}Oat Milk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class OatMilk extends CondimentDecorator {
/** @var Berverage */
private $berverage;
public function __construct(Berverage $berverage) {
$this->berverage = $berverage;
}
public function getDescription() {
return $this->berverage->getDescription() . ', Oat Milk';
}
public function getCost() {
return $this->berverage->getCost() + 25;
}
}測試:點餐
根據上面的設定,我們可以選擇兩種飲品,以及可添加的材料也有兩種,
今天有一位客人想要點一杯Expresso 加一份牛奶,則我們可以透過程式來實做:
1 |
|
思考
這邊跳過Order 的實做,也許可以朝著有顧客的姓名、內用還是外帶、桌號等等的方向進行,
就留給大家在練習的時候可以試著建立一張訂單看看。
針對今天練習的部分,未來可以擴充的彈性就比較大,比方說:
未來可以將常見的比例設為產品,拿鐵是Expresso 加 一份牛奶;馥列白可能是加兩份牛奶;摩卡則是加巧克力等等,
雖然會有不同方向的變化,但是都是在我們設定好的基礎飲品+調味品的模式上運作著。
以上是今天的設計模式筆記-裝飾器模式,如有謬誤或是想要一起討論,歡迎來信,謝謝!