前言
今天是2020年的第一天,在这里祝大家元旦快乐!之前用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()的抽象方法来让子类计算价格。逻辑没问题啊,如果你想增加一种咖啡的话,直接增加子类不就好了吗?
技术锦鲤:但是之前没有考虑到一个问题,咖啡可以加入各种调料,比如:蒸奶、豆浆、摩卡,但这些公司的系统就无能为力了。
小星:也可以啊,比如你有DarkRoast加牛奶,你只需建一个MilkDarkRoast类继承Beverage就可以了,还比如你有DarkRoast加摩卡,你只需再建一个MochaDarkRoast类继承Beverage就可以了啊。
技术锦鲤:对,是可以这样来实现,但是你想过吗?如果咖啡种类少了还行,要是有很多呢?你好好想想。
小星在脑海中想出了下面这幅图:
小星:对哦,这样的话类就太多了,而且很多重复的东西,那应该怎么解决呢?
技术锦鲤:你可以换个思路,既然继承无法解决这个问题,那么可以采用不一样的做法:我们可以将Beverage作为主体,然后在运行时以调料(蒸奶、豆浆、摩卡等)来装饰Beverage,就像你刚才举的例子:我们只需拿一个DarkRoast对象,然后来选择用牛奶或摩卡来装饰(Decorate)就可以了。
小星:我听得有点懵,您能具体说说吗?
技术锦鲤:你可以创建一个CondimentDecrator的抽象类来继承Beverage,然后你其他所有的调料就都可以抽出来继承CondimentDecrator,这样你只需要选择好咖啡,然后再选择你需要的调料就行了,而且还可以添加多种调料。
下面是技术锦鲤给的图:
小星:我好像有点明白了。
技术锦鲤:那你看看修改以下你的代码吧。
小星听从锦鲤的指导,刚才建的咖啡类没做改动,新增加了一个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中加了两份摩卡和一份奶油,还有就是价钱看看算的对不对哦。
小星忐忑地点了运行按钮:
技术锦鲤:不错不错,小星写出来了,你已经掌握了装饰者模式,“在不改变对象自身的基础上,动态地给一个对象添加一些额外的职责。”你已经做到了。但是有点小问题,你的价格出来的结果可不太对,虽然可以忽略不记,但是写程序一定要严谨。给你点提示吧,你可以去查一下BigDecimal这个类,你就知道你的计算精度问题了。
小星:好嘞,谢谢锦鲤。
小星很开心,学习了一种设计模式,感觉很巧妙,好像还有二十二种,啊。。。。慢慢来吧。
来源:CSDN
作者:Android_zhu_jiang
链接:https://blog.csdn.net/haojiagou/article/details/103795344