装饰者模式
定义:动态的将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
另一种表达方式:对原有的物体进行装饰,给原有的物体添加上新的装饰品。
装饰者模式很好的体现了 开放关闭原则,即类应该对扩展开放 对修改关闭。
举例说明:
有一个礼物,我们想要对其进行包装,礼物是被装饰者 即 组件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()方法