设计模式-装饰模式

装饰模式 参考

  装饰模式又名包装(Wrapper)模式。装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。

装饰模式的结构

  装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任。换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不使用创造更多子类的情况下,将对象的功能加以扩展。

装饰模式的角色有:

  • 抽象构件(Component)角色: 给出一个抽象接口,以规范准备接收附加责任的对象。
  • 具体构件(ConcreteComponent)角色: 定义一个将要接收附加责任的类。
  • 装饰(Decorator)角色: 持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
  • 具体装饰(ConcreteDecorator)角色: 负责给构件对象“贴上”附加的责任。

具体例子

使用装饰模式的方案来处理咖啡店订单

类图

 

package decorator.Demo

/**
 * 抽象类,Component角色
 * */
abstract class Drink {

    open var description: String = ""
        //getter缺省为默认
        set(value) {
            //field关键字指向属性本身
            field = value
        }

    open var price = 0.0f

    abstract fun cost(): Float

}

 

package decorator.Demo

/**
 * 具体构件角色, ConcreteComponent
 * */
open class Coffee : Drink() {

    override fun cost(): Float {
        return super.price
    }
}
package decorator.Demo

/**
 * 美式咖啡
 * */
class AmericanCoffee : Coffee() {

    init {
        description = "American Coffee"
        price = 5.0f
    }
}
package decorator.Demo

/**
 * Espresso咖啡
 * */
class Espresso : Coffee() {

    init {
        description = "Espresso"
        price = 6.0f
    }
}
package decorator.Demo

/**
 * 装饰者角色,Decorator, 相当于可以加到单品咖啡的调味品
 * */
open class Decorator constructor(drink: Drink) : Drink() {

    //被装饰者对象,这里是单品咖啡
    private var obj: Drink? = null

    init {
        this.obj = drink
    }

    override fun cost(): Float {
        //自已的价格 + 单品咖啡的价格
        return super.price + obj!!.cost()
    }

    override var description: String = ""
        get() = "${super.description} ${super.price}元 && ${obj!!.description}"
        set(value) {
            //field关键字指向属性本身
            field = value
        }
}
package decorator.Demo

/**
 * 具体装饰角色, ConcreteDecorator,这里是调味品牛奶
 * */
class Milk constructor(drink: Drink) : Decorator(drink) {

    init {
        //此调味品的描述
        description = "milk"
        //此调味品的价格
        price = 2.0f
    }
}
package decorator.Demo

/**
 * 具体装饰角色, ConcreteDecorator,这里是调味品巧克力
 * */
class Chocolate constructor(drink: Drink): Decorator(drink) {

    init {
        //此调味品的描述
        description = "chocolate"
        //此调味品的价格
        price = 3.0f
    }
}

代码测试

 

class CoffeeShop {
    init {
        //订单要求: 一杯美式咖啡,加上:2份chocolate + 1份milk
        var order: Drink = AmericanCoffee()
        println("${order.description}, 费用: ${order.cost()}")
        //order 加1份milk
        order = Milk(order)
        println("加入一份: milk, 费用: ${order.cost()}, 描述: ${order.description}")
        //order 加1份chocolate
        order = Chocolate(order)
        println("加入一份: chocolate, 费用: ${order.cost()}, 描述: ${order.description}")
    }
}

 结果

American Coffee, 费用: 5.0
加入一份: milk, 费用: 7.0, 描述:  2.0元 && American Coffee
加入一份: chocolate, 费用: 10.0, 描述:  3.0元 &&  2.0元 && American Coffee 

 

 装饰模式的优点

  1. 装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。装饰模式允许系统动态决定“贴上”一个需要的“装饰”,或者除掉一个不需要的“装饰”。继承关系则不同,继承关系是静态的,它在系统运行前就决定了。
  2. 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。

装饰模式的缺点

  由于使用装饰模式,可以比使用继承关系需要较少数目的类。使用较少的类,当然使设计比较易于进行。但是,在另一方面,使用装饰模式会产生比使用继承关系多更的对象。更多的对象会使得查错变得困难,特别是这些对象看上去都是很像。

 

设计模式在JAVA I/O库的中应用

  装饰模式在Java语言中的最著名的应用莫过于Java I/O标准库的设计了。

  由于Java I/O库需要很多性能的各种组合,如果这些性能都是用继承的方法实现的,那么每一种组合都需要一个类,这样就会造成大量性能重复的类出现。而如果采用装饰模式,那么类的数目就会大大减少,性能的重复也可以减至最少。因此装饰模式是Java I/O库的基本模式。

posted @ 2019-06-22 02:10  johnny_zhao  阅读(130)  评论(0编辑  收藏  举报