基本概念
装饰模式是动态的给一个对象添加一些额外的职责,相对于扩展功能来说,装饰模式比生成子类更加灵活。其实它的思想就在于向对象中去添加行为,而不去破坏其原有的风格,也就是说增加了新功能的对象是同一个类的加强版,就好比一张照片,我们给它增加了一个相框,任何增强的功能都可以进行动态的添加或者删除,因为相框其实本身就可以删除,这就是装饰。
装饰器模式允许向一个现有的对象添加新的功能,同时又不改变其结构。
相比之前我们要是扩展一个类的话是经常会使用继承的方式来实现,但是这样的话随着扩展功能的增多,子类会有很多很多。装饰模式很好的解决这个问题。
装饰者模式体现了一个原则:类应该对扩展开放,对修改关闭。
使用了装饰者模式类容易扩展,在不修改现有代码的情况下,就可以有以有新的行为。这样的好处在于:可以轻松的接受新的功能来应对改变的需求。这个是相当重要的。
什么时候会使用装饰模式
- 1、想要扩展一个类的功能,而这个类的功能经常变化的
- 2、对类的功能的扩展是可选的
- 3、在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
- 4、当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的 子类,使得子类数目呈爆炸性增长
结构图:
关于装饰模式的角色的划分
- 1、抽象构件类(Component):给出一个抽象接口,去规范一些功能,包含着这些类最基本的特性
- 2、具体构件类(ConcreteComponent):定义一个具体的对象,可以给这个对象去添加一些职责,也就是被装饰者
- 3、抽象装饰类(Decorator):有一个指向Component对象的实例,它是用于给具体的构件对象去添加新功能的,但是具体的功能添加在子类中实现。也就是装饰者类,当然抽象装饰者也可以继承抽象组件
- 4、具体装饰类(ConcreteDecorator):是抽象装饰类的子类,向组件去添加新功能
下面就简单的介绍下装饰模式的案例
主要就是手机和手机壳的关系,然后手机壳可以扩展手机的功能,比如让手机防尘、防水等
抽象构建者->手机
import UIKit
//抽象构建者->手机
protocol MobilePhone {
func showInfo()
}
具体构建者->具体的手机
class Phone: MobilePhone {
func showInfo() {
print("苹果手机")
}
}
抽象装饰者可以继承抽象组件,持有抽象组件的引用
class MobilePhoneShell: MobilePhone {
private var mobile:MobilePhone
init(mobile:MobilePhone) {
self.mobile = mobile
}
//显示详细信息
func showInfo() {
self.mobile.showInfo()
}
}
具体装饰者
class GoodPhoneShell: MobilePhoneShell{
override init(mobile:MobilePhone) {
super.init(mobile: mobile)
}
func wearproof()
{
print("耐磨功能")
}
func waterproof()
{
print("防水功能")
}
func dustproof()
{
print("防尘功能")
}
}
具体使用,就相当于是这个装饰者让手机多了防尘那些功能
let phone = Phone()
let goodshell = GoodPhoneShell(mobile: phone)
goodshell.showInfo()
goodshell.wearproof()
goodshell.waterproof()
还有就是装饰模式方便组合,这里就以上面的为基础进行构建出组合功能
抽象组件->手机
import UIKit
//抽象组件->手机
protocol MobilePhone {
//显示手机信息的方法
func showInfo()
//防晒的方法
func preventBask()
}
具体组件->具体的手机
import UIKit
//具体组件->具体的手机
class Phone: MobilePhone {
func preventBask() {
print("浅度防晒")
}
func showInfo() {
print("苹果手机")
}
}
抽象装饰者
import UIKit
//抽象装饰者可以继承抽象组件,持有抽象组件的引用
class MobilePhoneShell: MobilePhone {
private var mobile:MobilePhone
//防晒功能默认调用手机本身的功能,需要进行扩展的时候再去做扩展
func preventBask()
{
self.mobile.preventBask()
}
init(mobile:MobilePhone) {
self.mobile = mobile
}
//显示详细信息
func showInfo() {
self.mobile.showInfo()
}
}
具体装饰者 GoodPhoneShell
import UIKit
//具体装饰者
class GoodPhoneShell: MobilePhoneShell{
override init(mobile:MobilePhone) {
super.init(mobile: mobile)
}
func wearproof()
{
print("耐磨功能")
}
func waterproof()
{
print("防水功能")
}
func dustproof()
{
print("防尘功能")
}
}
具体装饰者 hardPhoneShell
import UIKit
//具体装饰者
class hardPhoneShell: MobilePhoneShell {
//初始化方法
override init(mobile:MobilePhone) {
super.init(mobile: mobile)
}
override func preventBask() {
print("深度防晒")
}
}
组合使用,下面就可以通过一个装饰者对象调用另外一个装饰者对象拥有的特性功能了
let phone = Phone()
let goodshell = GoodPhoneShell(mobile: hardPhoneShell(mobile: phone))
goodshell.showInfo()
goodshell.wearproof()
goodshell.waterproof()
//特性功能
goodshell.preventBask()
装饰模式在ios中其实也可以通过分类来体现,通过分类去给类添加新功能,不需要去进行子类化来扩展功能了,它虽然不符合装饰模式的结构,但是其实也是实现了装饰模式要做的事情,如果我们仅仅需要很少的装饰,其实就可以考虑用分类。