Kotlin设计模式实现之装饰者模式(Decorator)

简介: 装饰者模式(Decorator):在不改变对象自身的基础上,动态地给一个对象添加一些额外的职责。与继承相比,装饰者是一种更轻便灵活的做法。若要扩展功能,装饰者提供了比继承更有弹性的替代方法。

前言      

之前用kotlin实现了策略模式,文中写到要多写几篇文章来加深以下对设计模式的理解。那么今天要写的看题目应该就知道了:装饰者模式(也叫装饰模式)。下面是装饰者模式的定义:

装饰者模式(Decorator):在不改变对象自身的基础上,动态地给一个对象添加一些额外的职责。与继承相比,装饰者是一种更轻便灵活的做法。若要扩展功能,装饰者提供了比继承更有弹性的替代方法。

故事场景

小星刚毕业,到一家公司实习。今天来到公司后,一如既往地开始编写它的增删改查。

刚刚坐下打开电脑,技术锦鲤走了过来,小星内心开始发牢骚(锦鲤来干啥,每回它来都没好事)。锦鲤告诉小星,公司想要编写一个卖咖啡的系统,有不同种类的咖啡,需要能计算出咖啡的钱和区分咖啡的类别。

小星:没问题,很简单。

十分钟后,小星写出了它的第一版代码:

咖啡的基类:

abstract class Beverage(var description: String = "Unknown Beverage") {
    //描述
    open fun getDescriptions():String{
        return description
    }
    //价钱
    abstract fun cost():Double
}
其他咖啡(子类):
/**
 * 深度烘焙咖啡(星巴克)
 *
 * @author jiang zhu on 2020/1/1
 */
class DarkRoast:Beverage() {
    init {
        description = "DarkRoast"
    }
    override fun cost(): Double {
        return 2.99
    }
}
/**
 * 意式浓缩咖啡(星巴克)
 *
 * @author jiang zhu on 2019/12/16
 */
class Espresso:Beverage() {
    init {
        description = "Espresso"
    }
    override fun cost(): Double {
        return 1.99
    }
}


技术锦鲤:你这个卖咖啡看着有问题啊。


小星:没问题啊,您看啊,咱们有一个Beverage的抽象类,里面有getDescription()记录咖啡的描述,还有一个cost()的抽象方法来让子类计算价格。逻辑没问题啊,如果你想增加一种咖啡的话,直接增加子类不就好了吗?

20200101201343369.png



技术锦鲤:但是之前没有考虑到一个问题,咖啡可以加入各种调料,比如:蒸奶、豆浆、摩卡,但这些公司的系统就无能为力了。


小星:也可以啊,比如你有DarkRoast加牛奶,你只需建一个MilkDarkRoast类继承Beverage就可以了,还比如你有DarkRoast加摩卡,你只需再建一个MochaDarkRoast类继承Beverage就可以了啊。


技术锦鲤:对,是可以这样来实现,但是你想过吗?如果咖啡种类少了还行,要是有很多呢?你好好想想。


小星在脑海中想出了下面这幅图:

20200101201554960.png


小星:对哦,这样的话类就太多了,而且很多重复的东西,那应该怎么解决呢?


技术锦鲤:你可以换个思路,既然继承无法解决这个问题,那么可以采用不一样的做法:我们可以将Beverage作为主体,然后在运行时以调料(蒸奶、豆浆、摩卡等)来装饰Beverage,就像你刚才举的例子:我们只需拿一个DarkRoast对象,然后来选择用牛奶或摩卡来装饰(Decorate)就可以了。


小星:我听得有点懵,您能具体说说吗?


技术锦鲤:你可以创建一个CondimentDecrator的抽象类来继承Beverage,然后你其他所有的调料就都可以抽出来继承CondimentDecrator,这样你只需要选择好咖啡,然后再选择你需要的调料就行了,而且还可以添加多种调料。

下面是技术锦鲤给的图:


20200101203846756.png


小星:我好像有点明白了。


技术锦鲤:那你看看修改以下你的代码吧。


小星听从锦鲤的指导,刚才建的咖啡类没做改动,新增加了一个CondimentDecrator类:

abstract class CondimentDecorator:Beverage() {
    abstract override fun getDescriptions():String
}

将摩卡、蒸奶等调料建立类继承自CondimentDecrator:(注意在cost方法中要加上咖啡的价格,描述时也要加上咖啡的名称)

//摩卡
class Mocha(var beverage: Beverage):CondimentDecorator() {
    override fun getDescriptions(): String {
        return "${beverage.getDescriptions()},Mocha"
    }
    override fun cost(): Double {
        return 0.20+beverage.cost()
    }
}
//奶油
class Whip(var beverage: Beverage):CondimentDecorator() {
    override fun getDescriptions(): String {
        return "${beverage.getDescriptions()},Whip"
    }
    override fun cost(): Double {
        return 0.10+beverage.cost()
    }
}

小星:终于写完了,但是还不知道能不能成功。

技术锦鲤:你可以测试一下啊,来,我看着你测试。

小星在锦鲤的注视下写出了以下测试方法:


class Test {
    companion object {
        /** 我是main入口函数 **/
        @JvmStatic
        fun main(args: Array<String>) {
            var beverage2 : Beverage = DarkRoast()
            beverage2 = Mocha(beverage2)
            beverage2 = Mocha(beverage2)
            beverage2 = Whip(beverage2)
            println(beverage2.getDescriptions()+beverage2.cost())
        }
    }
}

技术锦鲤:点击运行吧,看看是不是DarkRoast中加了两份摩卡和一份奶油,还有就是价钱看看算的对不对哦。


小星忐忑地点了运行按钮:

20200101204838701.png


技术锦鲤:不错不错,小星写出来了,你已经掌握了装饰者模式,“在不改变对象自身的基础上,动态地给一个对象添加一些额外的职责。”你已经做到了。但是有点小问题,你的价格出来的结果可不太对,虽然可以忽略不记,但是写程序一定要严谨。给你点提示吧,你可以去查一下BigDecimal这个类,你就知道你的计算精度问题了。


小星:好嘞,谢谢锦鲤。

小星很开心,学习了一种设计模式,感觉很巧妙,好像还有二十二种,啊。。。。慢慢来吧。


目录
相关文章
|
8月前
|
设计模式
设计模式13 - 装饰模式【Decorator Pattern】
设计模式13 - 装饰模式【Decorator Pattern】
16 0
|
29天前
|
设计模式 Java
Java设计模式【十】:装饰者模式
Java设计模式【十】:装饰者模式
27 0
|
20天前
|
设计模式
设计模式之装饰器 Decorator
设计模式之装饰器 Decorator
27 1
|
29天前
|
设计模式 Java
【设计模式系列笔记】装饰者模式
装饰者模式是一种结构型设计模式,它允许你通过将对象放入包含行为的特殊封装类中来为原始对象添加新的行为。这种模式可以动态地将责任附加到对象上,而不影响其它对象。
42 11
|
29天前
|
设计模式 缓存 安全
设计模式-代理模式(静态代理、动态代理、cglib代理)、代理模式和装饰者模式的区别
设计模式-代理模式(静态代理、动态代理、cglib代理)、代理模式和装饰者模式的区别
|
29天前
|
设计模式 Go 开发工具
Golang设计模式——22装饰者模式
Golang设计模式——22装饰者模式
31 0
|
29天前
|
设计模式 Java
根据真实业务场景去实现一下设计模式中的装饰者模式
根据真实业务场景去实现一下设计模式中的装饰者模式
23 0
|
29天前
|
设计模式 人工智能 移动开发
认真学习设计模式之装饰者模式(Decorator Pattern)
写在前言 利用继承设计子类的行为,是在编译时静态决定的,而且所有的子类都会继承到相同的行为。然而如果能够利用组合的做法扩展对象的行为,就可以在运行时动态地进行扩展。通过动态地组合对象,可以写新的代码添加新功能,而无须修改现有代码。既然没有改变现有代码,那么引进bug或产生意外副作用的机会将大幅度减少。
30 0
|
8月前
|
设计模式 Java 关系型数据库
【设计模式——学习笔记】23种设计模式——装饰器模式Decorator(原理讲解+应用场景介绍+案例介绍+Java代码实现)
【设计模式——学习笔记】23种设计模式——装饰器模式Decorator(原理讲解+应用场景介绍+案例介绍+Java代码实现)
43 0
|
9月前
|
设计模式
设计模式~~~装饰者模式
设计模式~~~装饰者模式
22 0