6.装饰模式(大话设计模式kotlin版)

装饰模式

定义

装饰模式(Decorator),动态地给被装饰的对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更加灵活。

UML图

6.装饰模式(大话设计模式kotlin版)_第1张图片
Component 抽象组件,扮演底层的被装饰者。
ConcreteComponent 是具体的底层被装饰者。
Decorator 装饰基类,为被装饰者提供“装饰”功能。
ComponentDecorator具体的装饰者,提供具体的装饰。

基本代码实现

Component 抽象组件类

/**
 * @create on 2020/7/5 22:06
 * @description 抽象组件类
 * @author mrdonkey
 */
abstract class Component {
    abstract fun operation()
}

ConcreteComponent 具体的组件类

/**
 * @create on 2020/7/5 22:08
 * @description 具体组件
 * @author mrdonkey
 */
class ConcreteComponent : Component() {
    override fun operation() {
        println("具体组件对象的操作")
    }
}

Decorator 装饰基类,里面维持了一个被装饰者,即待装饰的组件。

/**
 * @create on 2020/7/5 22:09
 * @description 装饰类
 * @author mrdonkey
 */
open class Decorator : Component() {

    lateinit var component: Component//待装饰的组件

    override fun operation() {
        if (this::component.isInitialized) {
            component.operation()//执行component的operation方法
        }
    }
}

ConcreteDecoratorA 具体的装饰类,实现具体的装饰功能。

/**
 * @create on 2020/7/5 22:14
 * @description 具体的装饰者
 * @author mrdonkey
 */
class ConcreteDecoratorA: Decorator() {

    override fun operation() {
        super.operation()
        println("具体装饰对象A的操作")
        addBehaviorA()
    }

    /**
     * 装饰者A独有方法
     */
    private fun addBehaviorA(){

    }
}

…省略ConcreteDecorator

Client 客户端

/**
 * @create on 2020/7/5 22:18
 * @description 客户端
 * @author mrdonkey
 */
class Client {
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            val component = ConcreteComponent()
            val decoratorA = ConcreteDecoratorA()
            val decoratorB = ConcreteDecoratorB()

            //decoratorA包装component
            //decoratorB包装decoratorA
            //....层层装饰(包装)
            //本质上将装饰的component对象串联成单链表,最终逐个调用其operation方法
            decoratorA.component = component
            decoratorB.component = decoratorA
            decoratorB.operation()
        }
    }
}

装饰模式是利用 setComponent来对对象进行层层包装的,这样每个对象的实现就和如何使用的这个对象分离开了,每个装饰对象只关心自己的功能,不需要关心如何被添加到对象链中。

测试结果

具体组件对象的操作
具体装饰对象A的操作
具体装饰对象B的操作

简单的应用:人的装扮

人每天的装扮也是一个装饰模式应用。
人作为底层被装饰者,穿上衣服和裤子、鞋子都是被装饰的过程。

UML 图

6.装饰模式(大话设计模式kotlin版)_第2张图片

基本实现代码

Person 人,基础的被装饰对象

/**
 * @create on 2020/7/5 22:27
 * @description 人
 * @author mrdonkey
 */
open class Person constructor() {

    private var name: String? = null

    constructor(name: String) : this() {
        this.name = name
    }

    open fun show() {
        println("$name 今天的装扮")
    }
}

Finery 服饰类

/**
 * @create on 2020/7/5 22:30
 * @description 服饰类
 * @author mrdonkey
 */
open class Finery : Person() {

    lateinit var component: Person//被装饰对象

    override fun show() {
        if (this::component.isInitialized) {
            component.show()
        }
    }
}

TShirt t 恤类,具体的装饰

/**
 * @create on 2020/7/5 22:34
 * @description T恤
 * @author mrdonkey
 */
class TShirts : Finery() {

    override fun show() {
        println("穿上T恤")
        super.show()
    }
}

JeansShoes 省略…

Client 客户端

/**
 * @create on 2020/7/5 22:37
 * @description 客户端
 * @author mrdonkey
 */
class Client {
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            val zs = Person("张三")

            val shoes = Shoes()
            val tShirts = TShirts()
            val jeans = Jeans()

            tShirts.component = zs//张三穿上t恤
            jeans.component = tShirts//张三穿上牛仔
            shoes.component = jeans//张三穿上鞋
            shoes.show()//穿完了!
            //...可以为张三换其他的装饰
        }
    }
}

测试结果

穿上鞋子
穿上牛仔裤
穿上T恤
张三 今天的装扮

总结

应用场景

  • 当系统需要新功能的时候。它把每个要装饰的功能放在单独的类中,并让这个类包装它所要装饰的对象(而不是向旧类中添加新的代码,增加旧类的复杂度)。因此,当需要执行特殊行为时,客户代码就可以在运行时根据需要有选择地、按顺序地使用装饰功能包装对象。

优势

  • 把类中的装饰功能从类中搬移去除,简化原有的类。
  • 优先地把类的职责和装饰功能区分开。去除相关类中重复的装饰逻辑。

与建造者模式的区别

  • 建造者模式与装饰模式都是在内部组装完成,最后才显示出来;但建造者模式建造过程是稳定的,而装饰者的装饰过程是不稳定的。

你可能感兴趣的:(设计模式)