装饰者模式学习笔记1_咖啡

装饰者模式类图:
在这里插入图片描述
装饰者模式(Decorator)也叫包装模式(Wrapper),
装饰者也可以命名 为 XXWrapper, 实现抽象组件 并持有 被装饰者的引用, 其它地方只能调用 XXWrapper ,
再由XXWrapper 调用 被装饰者 (最终实现在被装饰者) – (有点像代理模式???)

1.原理

动态的将新功鲜附加到对象上,在对象功能扩展方面,它比继承更有弹性,符合开闭原则

2. 需求例子

星巴克咖啡订单
需求:

  1. 单品咖啡: 意大利咖啡(Espresso ) ShortBlack
    美式咖啡(LongBlack) 无糖咖啡(Decaf)
  2. 调料:豆浆(Soy) 牛奶(Milk)
  3. 点单可以是单品+调料组合,最后算价格
  4. 扩展性好,方便维护

3. 普通实现

单品咖啡 + 调料 组合
缺点:类可能是全排列的数量,出现类爆炸

4. 改进实现

在单品咖啡中包含各种调料的判断,
在计算价格的时候,根据是否有各种调料、调料的价格等,算出最终的价格
优点:控制了类的数量,避免了类爆炸
数量:当增加一种调料时,需要在单品咖啡中,增加该调料的(是否有以及价格的增加),不利于扩展

5.装饰者模式

反向实现,把单品咖啡当做被装饰者,调料作为装饰者,装饰者中包含具体的装饰者
类图
在这里插入图片描述
代码

1. 基类

abstract class Drink {
    // 描述
    var description: String? = null
    // 价格
    var price: Float = 0.0f

    // 最终的价格
    abstract fun cost(): Float
    // 主要用于装饰者中获取最终的描述 (装饰者本身的描述 +  被装饰者的描述)
    abstract fun getFinalDescription(): String?
}

2. Coffee 抽象类

abstract class Coffee: Drink {
    constructor()

    // 返回被装饰者的价格
    override fun cost(): Float {
        return price
    }

    // 返回被装饰者的描述
    override fun getFinalDescription(): String? {
        return description
    }
}

3. Coffee 子类1

class LongBlack : Coffee {
    // 只需设置 被装饰者的描述 和 价格
    constructor() {
        description = " 美式咖啡  "
        price = 6.0f
    }
}

4. Coffee 子类2

class DeCof : Coffee{
    constructor() {
        description = " 无因咖啡 "
        price = 5.0f
    }
}

5. 装饰者抽象类

open class Decorator : Drink{
    // 持有被装饰者引用
    var obj: Drink

    constructor(obj: Drink) : super() {
        this.obj = obj
    }

    // 装饰者本身的价格 +  被装饰者的价格
    override fun cost(): Float {
        return price + obj.cost()
    }

    // 装饰者本身的描述 +  被装饰者的描述
    override fun getFinalDescription(): String? {
        return description + obj.getFinalDescription()
    }
}

6. 装饰者实现类1

    // 需要传入被装饰者对象的引用, 并初始化装饰者自身的描述 和 价格
    constructor(obj: Drink) : super(obj) {
        description = "豆浆"
        price = 1.5f
    }

7. 装饰者实现类2

    constructor(obj: Drink) : super(obj) {
        description = " 牛奶 "
        price = 3.0f
    }

8. 测试代码

    @Test
    fun testDecorator1(){
        // order 声明为接口
        var order:Drink = LongBlack()
        printResult(order)

        order = Soy(order)
        printResult(order)

        order = Soy(order)
        printResult(order)

        order = Soy(order)
        printResult(order)

        order = Milk(order)
        printResult(order)

        order = DeCof()
        printResult(order)

        order = Milk(order)
       printResult(order)

        order = Soy(order)
        printResult(order)

        //useBuilderTest()
    }
    private fun printResult(order:Drink){
        Log.d(TAG, "买了 ${order.getFinalDescription()}, 总费用为 ${order.cost()}")
    }

9. 运行结果

07-30 10:52:01.226 D 28857    28929    DecoratorTest:    买了  美式咖啡  , 总费用为 6.0 
07-30 10:52:01.226 D 28857    28929    DecoratorTest:    买了 豆浆 美式咖啡  , 总费用为 7.5 
07-30 10:52:01.227 D 28857    28929    DecoratorTest:    买了 豆浆豆浆 美式咖啡  , 总费用为 9.0 
07-30 10:52:01.227 D 28857    28929    DecoratorTest:    买了 豆浆豆浆豆浆 美式咖啡  , 总费用为 10.5 
07-30 10:52:01.227 D 28857    28929    DecoratorTest:    买了  牛奶 豆浆豆浆豆浆 美式咖啡  , 总费用为 13.5 
07-30 10:52:01.227 D 28857    28929    DecoratorTest:    买了  无因咖啡 , 总费用为 5.0 
07-30 10:52:01.228 D 28857    28929    DecoratorTest:    买了  牛奶  无因咖啡 , 总费用为 8.0 
07-30 10:52:01.228 D 28857    28929    DecoratorTest:    买了 豆浆 牛奶  无因咖啡 , 总费用为 9.5 
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值