看一个项目需求
咖啡馆订单系统项目(咖啡馆):
1) 咖啡种类/单品咖啡:Espresso(意大利浓咖啡)、ShortBlack、LongBlack(美式咖啡)、Decaf(无因
咖啡)
2) 调料:Milk、Soy(豆浆)、Chocolate
3) 要求在扩展新的咖啡种类时,具有良好的扩展性、改动方便、维护方便
4) 使用 OO 的来计算不同种类咖啡的费用: 客户可以点单品咖啡,也可以单品咖啡+调料组合。
方案 1-较差的方案
这种方案把所有可能性都罗列出来继承了Drink
1) Drink 是一个抽象类,表示饮料
2) description 就是描述,比如咖啡的名字等
3) cost 就是计算费用,是一个抽象方法
4) Decaf 等等就是具体的单品咖啡,继承 Drink,并实现 cost 方法
5) Espresso&&Milk 等等就是单品咖啡+各种调料的组合,这个会很多..
6) 这种设计方式时,会有很多的类,并且当增加一个新的单品咖啡或者调料时,类的数量就会倍增( 类爆炸)
方案 2-好点的方案
前面分析到方案 1 因为咖啡单品+调料组合会造成类的倍增,因此可以做改进,将调料内置到 Drink
类,这样就不会造成类数量过多。从而提高项目的维护性(如图)=>同时违反 ocp,如果添加新的调料就会修改源代码,扩展性不好.
装饰者模式原理
1) 装饰者模式就像打包一个快递
主体:比如:陶瓷、衣服 (Component)
包装:比如:报纸填充、塑料泡沫、纸板、木板(Decorator)
2) Component 主体:比如类似前面的 Drink
3) ConcreteComponent 和 Decorator
ConcreteComponent:具体的主体,比如前面的各个单品咖啡
4) Decorator: 装饰者,比如各调料.
在如图的 Component 与 ConcreteComponent 之间,如果 ConcreteComponent 类很多,还可 以设计一个缓冲层,将共有的部分提取出来,抽象层一个类。
装饰者模式定义
1) 装饰者模式: 动态的将新功能附加到对象上。在对象功能扩展方面,它比 继承更有弹性( 递归),
装饰者模式也体现了开闭原则(ocp)
2) 这里提到的动态的将新功能附加到对象和 ocp 原则
用装饰者模式设计重新设计的方案
抽象父类Drink
//说明
//1. Drink 是表示饮品,是一个抽象类
abstract class Drink {
var description = ""
private var price = 0.0f
def setDescription(description: String): Unit = {
this.description = description
}
def getDescription(): String = {
description + " 价格: " + this.getPrice()
}
def getPrice(): Float = {
price
}
def setPrice(price: Float): Unit = {
this.price = price
}
//将计算成本的方法做成一个抽象方法cost
def cost(): Float
}
装饰者类,装饰Drink
//这个就是Decorator装饰者
class Decorator extends Drink {
//obj就是被装饰的对象Drink
//obj可以是单品咖啡,也可以是单品咖啡+调料的组合
private var obj: Drink = null
def this(obj: Drink) {
this
this.obj = obj
}
//这里我们实现了cost,这里使用了递归方式
override def cost(): Float = {
super.getPrice() + obj.cost()
}
//获取信息时,也需要递归获取
override def getDescription(): String = {
super.getDescription() + "&&" + obj.getDescription()
}
}
咖啡调料种类
class Chocolate(obj: Drink) extends Decorator(obj) {
super.setDescription("Chocolate")
//一份巧克力3.0f
super.setPrice(3.0f)
}
class Milk(obj: Drink) extends Decorator(obj) {
setDescription("Milk")
setPrice(2.0f)
}
咖啡种类,如果以后扩展别的饮品就容易扩展了.
//在Drink 和 单品咖啡,我做了一个缓冲层
//这里是为了扩展,针对当前项目可以不要
class Coffee extends Drink{
override def cost(): Float = {
super.getPrice()
}
}
class DeCaf extends Coffee {
//使用主构造器
super.setDescription("DeCaf")
super.setPrice(3.0f)
}
class LongBlack extends Coffee {
//使用主构造器
super.setDescription("LongBlack")
super.setPrice(5.0f)
}
测试主程序
object CoffeeBar {
def main(args: Array[String]): Unit = {
println("咖啡bar..")
val order: Drink = new DeCaf //点DeCaf单品咖啡
println("order1 price:" + order.cost()) //3.0
println("order1 desc:" + order.getDescription())
println("------------------------------------------")
// 点一份LongBlack,并加入1份Milk 和 2份Chocolate
var order2: Drink = new LongBlack //5.0
order2 = new Milk(order2) //2.0
order2 = new Chocolate(order2)//3.0
order2 = new Chocolate(order2)//3.0
order2 = new NewMilk(order2)
//
println("order2 price:"+order2.cost()); //
println("order2 desc:"+order2.getDescription())
//
//java.io.FilterInputStream
}
}