一、定义
装饰器模式(Decorator Pattern) 也称为包装模式(Wrapper Pattern) 是指在不改变原有对象的基础之上,将功能附加到对象上,提供了比继承更有弹性的替代方案(扩展原有对象的功能),属于结构型模式。装饰器模式的核心是功能扩展,使用装饰器模式可以透明且动态地扩展类的功能。
意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。
何时使用:在不想增加很多子类的情况下扩展类。
如何解决:将具体功能职责划分,同时继承装饰者模式。
二、优缺点
优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式(这个应该就是设计模式的七大设计原则中的合成复用原则),装饰模式可以动态扩展一个实现类的功能。
缺点:多层装饰比较复杂。
三、自己的理解
如果我们想给一个类,扩展一些功能,不考虑设计模式,肯定是直接就加属性,加方法,但是这种简单的添加是不符合对拓展开发,对修改关闭的设计原则,也不符合单一职责的设计原则。
接着可能会想到,我们可以继承原来的核心类,不同的功能各对应一个核心类的实现类,这种方法使得装饰这一行为符合了单一职责和对修改关闭对扩展开发,但是过多的继承会使类过多膨胀,每一个装饰实现类中都会有核心类的代码和功能,这有点不合适,从这一点来说又没有完全的符合单一职责的设计原则,这其实就是违背了合成复用原则。
最终解决办法,就是把要装饰的能力(要拓展的能力)抽象成接口,然后核心类实现这个接口,抽象装饰类也实现这个接口,在这个抽象装饰类定好和核心类的合作关系,一般是装饰类持有核心类的引用,这个引用用接口来声明(多态),那抽象装饰类中就该有一个方法来接收核心类的实例(可以是set方法或者构造方法),在抽象装饰类实现的装饰能力的方法中,要执行核心类的方法。装饰实现类就只实现用什么装饰(实现要拓展的能力)
四、代码实现
// 抽象出来的能力,画画
interface Component{
fun draw()
}
//核心类人实现,画画这个能力
class Person(var name : String) : Component{
override fun draw() {
println("${name}画了一座房子")
}
}
//抽象装饰类,定义了和核心类的关系,即持有核心类的引用,通过set方法把核心类的引用传递过来,因为抽象装饰类也实现了画画的能力,所以也要实现draw方法,并且调用核心类的draw方法,这样我们就可以在抽象装饰类的子类中添加新的装饰的同时,也调用核心类的方法
abstract class Decorator : Component{
var component : Component? = null
override fun draw() {
component?.draw()
}
}
//家具装饰类实现类
class DecoratorFurniture : Decorator() {
private fun drawFurniture(){
println("画上一些家具")
}
override fun draw() {
super.draw()
drawFurniture()
}
}
//植物装饰类实现类
class DecoratorPlant : Decorator(){
private fun drawPlant(){
println("画上花花草草")
}
override fun draw() {
super.draw()
drawPlant()
}
}
fun main() {
val person = Person("小明")
val decoratorFurniture = DecoratorFurniture()
val decoratorPlant = DecoratorPlant()
//用家具装饰房子
println("-------------------------------------------")
decoratorFurniture.component = person
decoratorFurniture.draw()
//用植物装饰房子
println("-------------------------------------------")
decoratorPlant.component = person
decoratorPlant.draw()
//用家具和植物装饰房子
println("-------------------------------------------")
decoratorFurniture.component = person
decoratorPlant.component = decoratorFurniture // 因为有好的设计,体会一下这里多态的使用,可以连续装饰
decoratorPlant.draw()
}