裝飾者模式
定義:動态的将責任附加到對象上,若要擴充功能,裝飾者提供了比繼承更有彈性的替代方案。
另一種表達方式:對原有的物體進行裝飾,給原有的物體添加上新的裝飾品。
裝飾者模式很好的展現了 開放關閉原則,即類應該對擴充開放 對修改關閉。
舉例說明:
有一個禮物,我們想要對其進行包裝,禮物是被裝飾者 即 元件Component,包裝盒以及包裝盒上的花等等就是裝飾品 即 裝飾者Decorator。
換成花瓶與鮮花,花瓶是Component,鮮花是Decorator。
一、通過示例認識裝飾者模式
場景:花瓶和鮮花的關系
根據設計原則“封裝變化” 即 要将變化的東西進行封裝提取。裝飾者模式中 所使用的裝飾就是變化的部分 即 對應着示例中的 鮮花,因為往花瓶中插花的過程就是鮮花變化的過程 即 為花瓶裝飾的過程,花瓶就是元件。
注意:
裝飾者 = 舊元件 + 新裝飾品
下方是元件與裝飾者之前的關系“類圖”
而我們要實作的 花瓶和鮮花 示例“類圖”如下所示
圖中上方紅框部分就是所有鮮花 即 裝飾者Decorator
下方紅框部分就是花瓶 即 元件Component
1、所有類的基類VaseComponent 即 花瓶元件
參數 | 說明 |
---|---|
description | 用來描述xxx花瓶裝有xxx花 |
函數 | 說明 |
---|---|
display() | 用來列印description描述資訊的 |
2、所有鮮花的基類FlowerDecorator
繼承自VaseComponent,因為裝飾者擁有被裝飾者對象的同時又需要添加新的裝飾物,是以無論是裝飾者還是被裝飾者都有共同的基類
參數 | 說明 |
---|---|
vase | VaseComponent的對象,可以是沒有任何裝飾的花瓶,也可以是已經添加了裝飾的花瓶 |
3、如何實作裝飾者模式?
利用 多态
4、具體實作
1)實作空花瓶的基類–VaseComponent
參數 | 說明 |
---|---|
description | 存儲的是花瓶的描述資訊,例如:瓷花瓶、玻璃花瓶 |
函數 | 說明 |
---|---|
getDescription() | 用來擷取description存儲的描述資訊的 |
display() | 對getDescription()擷取的值進行列印 |
//花瓶的基類
class VaseComponent{
//對花瓶進行描述
private var description : String
init(_ description : String = "花瓶") {
self.description = description
}
//擷取description存儲的描述資訊
func getDescription()->String{
return self.description
}
func display(){
//列印描述資訊
print(getDescription())
}
}
2)建立空花瓶
建立一個瓷花瓶Porcelain、一個玻璃花瓶Glass,等着其他鮮花來裝飾
函數 | 說明 |
---|---|
init() | 調用父類初始化時為父類中的description字段進行初始化 |
//建立特定的花瓶
class Porcelain : VaseComponent{
init() {
super.init("瓷花瓶:")
}
}
class Glass : VaseComponent{
init() {
super.init("玻璃花瓶:")
}
}
3)實作鮮花的基類—FlowerDecorator
參數 | 說明 |
---|---|
vase | 用于存儲舊元件 即 上一次被裝飾過的花瓶元件 |
函數 | 說明 |
---|---|
init(vase) | 裝飾者在初始化時會指定上次被修改後的元件 |
//鮮花的父類,因為裝飾者就是最新的花瓶元件,是以要繼承自VaseComponent
class FlowerDecorator : VaseComponent{
//用于存儲 “舊元件” 即上次被裝飾過的花瓶元件
var vase : VaseComponent
//“裝飾者”在初始化時會指定上次被修飾後的元件(空花瓶或者其他修飾者的對象)
init(_ vase : VaseComponent) {
self.vase = vase
}
}
4)實作各個裝飾者
函數 | 說明 |
---|---|
getDescription() | 重寫了基類的該方法,為上一個裝飾者添加新的裝飾品 |
//往花瓶裡加入特定的花進行裝飾
//玫瑰花
class Rose : FlowerDecorator{
override init(_ vase: VaseComponent) {
super.init(vase)
}
override func getDescription() -> String {
return vase.getDescription() + "玫瑰 "
}
}
//百合花
class Lily : FlowerDecorator{
override init(_ vase: VaseComponent) {
super.init(vase)
}
override func getDescription() -> String {
return vase.getDescription() + "百合 "
}
}
4、測試
//建立空花瓶
var porcelain : VaseComponent = Porcelain()
//列印最新的描述資訊
porcelain.display()
//插入玫瑰
porcelain = Rose(porcelain)
//插入百合
porcelain = Lily(porcelain)
//列印最新的描述資訊
porcelain.display()
測試結果
上述測試用例的具體調用方式如下:
1)我們為procelain對象添加了兩個裝飾品,最終的procelain對象是Lily對象,是 空瓷瓶+玫瑰+百合 的組合體
2)調用display()方法時,會調用該對象的 getDescription()方法,而該對象中的getDescription()方法會調用上一個裝飾者 即 Rose 對象的getDescription()方法,最終會找到 元件 即 空瓷瓶中的 getDescription()方法