动态的将责任附加到对象身上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案
看一个饮料喝调料的问题
1,消费者需要一杯咖啡
2,消费者提出要求:要加糖
3,消费者提出要求:要加两份牛奶
这个时候你会用什么方式来解决呢?
1,使用最原始的方法,记住每一种调料的价格和饮料的价格,最后+在一起。
减去相应的价格
。。。。
。。。。
怎么办呢?
2,使用装饰者,把饮料看做为被装饰者,调料为装饰者。
如果消费者忽然不要某种饮料呢?
删除对应的装饰者
或者说想要发票?
每种调料内都添加描述即可
种类非常多
创建 package 进行分类,如 碳酸饮料:,分为哪几种(可乐,雪碧等在一个package),调料分为哪几种(加冰,姜汁等,在一个 package中)!
1,首先定义饮料的抽象类
/**
* @name ModeDemo
* @class name:com.example.mode.decorate
* @author 345 QQ:1831712732
* @time 2020/1/6 21:29
* @description 饮料
*/
abstract class Beverage {
/**
* 未知的饮料
*/
var mDescription = "Unknown Beverage"
/**
* 获取饮料描述
*/
open fun getDescription(): String {
return mDescription
}
/**
* 计算价格
*/
abstract fun cost(): Double
}
2,创建饮料
/**
* @name ModeDemo
* @class name:com.example.mode.decorate
* @author 345 QQ:1831712732
* @time 2020/1/6 21:36
* @description 被装饰者:浓缩咖啡
*/
class Espresso : Beverage() {
init {
mDescription = "浓缩咖啡"
}
/**
* 浓缩咖啡的价格
*/
override fun cost(): Double {
return 32.00
}
}
/**
* @author 345 QQ:1831712732
* @name ModeDemo
* @class name:com.example.mode.decorate
* @time 2020/1/6 21:38
* @description 被装饰者:混合咖啡
*/
class HouseBlend : Beverage() {
init {
mDescription = "混合咖啡"
}
override fun cost(): Double {
return 50.00
}
}
3,创建调料抽象类
/**
* @name ModeDemo
* @class name:com.example.mode.decorate
* @author 345 QQ:1831712732
* @time 2020/1/6 21:33
* @description 装饰者类(调料),例如给咖啡添加牛奶,糖等,需要继承此类
*/
abstract class CondimentDecorator : Beverage() {
/**
* 调料的描述
*/
abstract override fun getDescription(): String
}
4,创建具体的调料类
/**
* @name ModeDemo
* @class name:com.example.mode.decorate.seasoning
* @author 345 QQ:1831712732
* @time 2020/1/6 21:46
* @description 装饰者:牛奶
*/
class Milk(private val beverage: Beverage) : CondimentDecorator() {
override fun getDescription(): String {
return beverage.getDescription() + ",牛奶"
}
/**
* 价格
*/
override fun cost(): Double {
return 5.00 + beverage.cost()
}
}
/**
* @name ModeDemo
* @class name:com.example.mode.decorate.seasoning
* @author 345 QQ:1831712732
* @time 2020/1/6 21:55
* @description 装饰者:糖
*/
class Sugar(private val beverage: Beverage) : CondimentDecorator() {
/**
* 描述
*/
override fun getDescription(): String {
return beverage.getDescription() + ",糖"
}
/**
* 价格
*/
override fun cost(): Double {
return 4.00 + beverage.cost()
}
}
/**
* @name ModeDemo
* @class name:com.example.mode.decorate.seasoning
* @author 345 QQ:1831712732
* @time 2020/1/6 21:58
* @description 装饰者:奶油
*/
class Whip(private val beverage: Beverage) : CondimentDecorator() {
override fun getDescription(): String {
return beverage.getDescription() + ",奶油"
}
/**
* jia价格
*/
override fun cost(): Double {
return 6.00 + beverage.cost()
}
}
5,测试
/**
* @name DesignModeDemo
* @class name:com.example.mode.decorate
* @author 345 QQ:1831712732
* @time 2020/1/6 22:00
* @description
*/
fun main() {
/**
* 一杯浓缩咖啡,加糖,牛奶
*/
val milk = Milk(Sugar(Espresso()))
println(milk.getDescription() + " ¥" + milk.cost())
/**
* 一杯杯混合咖啡,加牛奶,两份奶油
*/
val whip = Whip(Whip(Milk(HouseBlend())))
println(whip.getDescription() + " ¥" + whip.cost())
}
浓缩咖啡,糖,牛奶 ¥41.0
混合咖啡,牛奶,奶油,奶油 ¥67.0
**1,**如果消费者忽然不要某种饮料呢?例如:两份牛奶换成一份
这个比较麻烦了,需要修改代码(一般情况不会这样做,下面会给出解释)。给调料抽象类添加如下代码:
abstract class CondimentDecorator : Beverage() {
/**
* 调料的描述
*/
abstract override fun getDescription(): String
abstract fun setCondiment(condiment: CondimentDecorator)
}
实现类
class Whip(private var beverage: Beverage) : CondimentDecorator() {
override fun setCondiment(condiment: CondimentDecorator) {
beverage = condiment
}
override fun getDescription(): String {
return beverage.getDescription() + ",奶油"
}
/**
* 价格
*/
override fun cost(): Double {
return 6.00 + beverage.cost()
}
}
其他的实现类都是如此
测试
fun main() {
/**
* 一杯杯混合咖啡,加牛奶,两份奶油
*/
val whip = Whip(Whip(Milk(HouseBlend())))
println(whip.getDescription() + " ¥" + whip.cost())
val houseBlend = HouseBlend()
val listOf = mutableListOf<CondimentDecorator>()
//两份奶油,一份牛奶
listOf += Whip(houseBlend)
listOf += Whip(houseBlend)
listOf += Milk(houseBlend)
for (i in 0 until listOf.size) {
if (i < listOf.size - 1) {
listOf[i].setCondiment(listOf[i + 1])
}
}
println(listOf[0].getDescription() + " ¥" + listOf[0].cost())
//取消一个牛奶,这里可以直接删除引用
listOf.removeAt(0)
println(listOf[0].getDescription() + " ¥" + listOf[0].cost())
}
混合咖啡,牛奶,奶油,奶油 ¥67.0
混合咖啡,牛奶,奶油,奶油 ¥67.0
混合咖啡,牛奶,奶油 ¥61.0
看起来麻烦了一些。其实代码还是很好理解的
原来都是通过构造方法进行装饰,但是现在增加了一个 set 方法。通过 set 也可以进行装饰
代码还可以进行更好的优化
当然了,一般情况下也不需要这种代码。因为装饰是一次性的。就像 JAVA 的 IO 一样,也是用的是装饰者模式,你不可能装饰后在减掉某个装饰板。这里只是一个扩展
2,3
这两个问题都差不多。只要添加相应的调料和饮料即可。
参考自 Head First