Scala 装饰者模式

看一个项目需求

咖啡馆订单系统项目(咖啡馆)

1)咖啡种类/单品咖啡:Espresso(意大利浓咖啡)、ShortBlack、LongBlack(美式咖啡)、Decaf(无因咖啡)
2)调料:Milk、Soy(豆浆)、Chocolate
3)要求在扩展新的咖啡种类时,具有良好的扩展性、改动方便、维护方便
4)使用**OO(面向对象)**的来计算不同种类咖啡的费用: 客户可以点单品咖啡,也可以单品咖啡+调料组合。

方案一:

在这里插入图片描述

方案1-小结和分析

1)Drink 是一个抽象类,表示饮料
2)description就是描述,比如咖啡的名字等
3)cost就是计算费用,是一个抽象方法
4)Decaf 等等就是具体的单品咖啡,继承Drink,并实现cost方法
5)Espresso&&Milk 等等就是单品咖啡+各种调料的组合,这个会很多…
6)这种设计方式时,会有很多的类,并且当增加一个新的单品咖啡或者调料时,类的数量就会倍增(类爆炸)

方案二:
将调料内置到Drink 类中,这样就不会造成类的数量过多
在这里插入图片描述

分析:
方案2可以控制类的数量,不至于造成过多的类。
在增删调料种类时,代码维护量仍然很大。


装饰者模式

装饰者模式原理

1)装饰者模式就像打包一个快递
主体:比如:陶瓷、衣服 (Component)
包装:比如:报纸填充、塑料泡沫、纸板、木板(Decorator)
2)Component
主体:比如类似前面的Drink

3)ConcreteComponent和Decorator ConcreteComponent:具体的主体,比如前面的各个单品咖啡 Decorator: 装饰者,比如各调料.
4)在如图的Component与ConcreteComponent之间,如果ConcreteComponent类很多,还可以设计一个缓冲层,将共有的部分提取出来,抽象层一个类。

在这里插入图片描述

装饰者模式定义

1)装饰者模式:动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性,装饰者模式也体现了开闭原则(ocp)(功能扩展开放,代码(已有的)修改关闭)

2)这里提到的动态的将新功能附加到对象和ocp原则,在后面的应用实例上会以代码的形式体现,请同学们注意体会。

通过装饰者模式设计的方案
在这里插入图片描述
在这里插入图片描述

Drink 设定标准,设置价格,获取价格等操作

代码结构:
在这里插入图片描述
Coffee,DeCaf,Espresso,LongBlack,ShortBlack 都继承自Drink。
Chocolate,Milk,NewMilk,Soy 都是继承自 Decorator。
Decorator 也继承自 Drink。

代码:
主程序:

import Decorator.coffeebar.mycoffee.{DeCaf, LongBlack}
import Decorator.coffeebar.mydecorator.{Chocolate, Milk, NewMilk}

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("order3 price:"+order2.cost()); //
    println("order3 desc:"+order2.getDescription())
  }
}

我觉得这里可以换成这样更容易理解,每一次都将上一个对象给包装了起来。
这里var 可以看到是灰色的。但是如果是上面代码中的写法,order2 需要时var 类型的
在这里插入图片描述
输出结果:
在这里插入图片描述

Drink类:

package Decorator.coffeebar

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
}

Decorator:

package Decorator.coffeebar.mydecorator

import Decorator.coffeebar.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()
  }
}

Decorator 继承自 Drink。里面提供了辅助构造器可以传入 Drink 对象。
Decorator 的子类在创建实例的时候就可以传入 Drink 的子类实例
而子类中会设置相应的方法,在被调用时就会自动执行

咖啡种类:
Coffee:

import Decorator.coffeebar.Drink

//在Drink 和  单品咖啡,做了一个缓冲层
//这里是为了扩展,针对当前项目可以不要
class Coffee extends Drink{
  override def cost(): Float = {
    super.getPrice()
  }
}

DeCaf:

//在Drink 和  单品咖啡,做了一个缓冲层
//这里是为了扩展,针对当前项目可以不要

class DeCaf extends Coffee {

  //使用主构造器
  super.setDescription("DeCaf")
  super.setPrice(3.0f)
}

Espresso:

//这个是单品咖啡,在装饰者设计模式中ConcreteComponent
class Espresso extends Coffee {
  //使用主构造器
  super.setDescription("Espresso")

  super.setPrice(6.0f)
}

LongBlack:

class LongBlack extends Coffee {
  //使用主构造器
  super.setDescription("LongBlack")
  super.setPrice(5.0f)
}

ShortBlack:

class ShortBlack extends Coffee {
  //使用主构造器
  super.setDescription("ShortBlack")
  super.setPrice(4.0f)
}

调料种类:
Chocolate:

import Decorator.coffeebar.Drink

class Chocolate(obj: Drink) extends Decorator(obj) {

  super.setDescription("Chocolate")
  //一份巧克力3.0f
  super.setPrice(3.0f)

}

Milk:

import Decorator.coffeebar.Drink

class Milk(obj: Drink) extends Decorator(obj) {

  setDescription("Milk")
  setPrice(2.0f)
}

NewMilk:

import Decorator.coffeebar.Drink

class NewMilk(obj: Drink) extends Decorator(obj) {

  setDescription("新式Milk")
  setPrice(4.0f)
}

Soy:

import Decorator.coffeebar.Drink

class Soy(obj: Drink) extends Decorator(obj) {
  setDescription("Soy")
  setPrice(1.5f)
}

ocp开闭原则:功能扩展开放,代码(已有的)修改关闭

----观看韩顺平老师Scala视频笔记

猜你喜欢

转载自blog.csdn.net/weixin_45468845/article/details/106379855