装饰者模式类图:
装饰者模式(Decorator)也叫包装模式(Wrapper),
装饰者也可以命名 为 XXWrapper, 实现抽象组件 并持有 被装饰者的引用, 其它地方只能调用 XXWrapper ,
再由XXWrapper 调用 被装饰者 (最终实现在被装饰者) – (有点像代理模式???)
1.原理
动态的将新功鲜附加到对象上,在对象功能扩展方面,它比继承更有弹性,符合开闭原则
2. 需求例子
星巴克咖啡订单
需求:
- 单品咖啡: 意大利咖啡(Espresso ) ShortBlack
美式咖啡(LongBlack) 无糖咖啡(Decaf) - 调料:豆浆(Soy) 牛奶(Milk)
- 点单可以是单品+调料组合,最后算价格
- 扩展性好,方便维护
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