装饰者模式介绍和咖啡店应用实例 | 学习笔记

简介: 快速学习装饰者模式介绍和咖啡店应用实例

开发者学堂课程【Scala 核心编程 - 进阶装饰者模式介绍和咖啡店应用实例学习笔记,与课程紧密连接,让用户快速学习知识。

课程地址https://developer.aliyun.com/learning/course/610/detail/9139


装饰者模式介绍和咖啡店应用实例


内容介绍

一、原理

二、设计方案

三、代码

四、举例

五、总结


一、原理

装饰者模式就像打包快递一样,例如在淘宝上买了陶瓷产品或者买了一件衣服,商家先用报纸或者塑料泡沫包裹,主体就是陶瓷或者衣服,主体叫 component,由主体引申出 concretecomponent,concrete 是混凝土的意思,decorator 就是装饰者,可以理解成各种调料,这样就形成新的关系,

在 component 和 creatcomponent 之间,可以设计缓冲层,也可以不设计, decorator 也会继承 drink,两者都成为了 component 的子类,就可以进行装饰。

比如 concrete 对应具体的主体,比如单品咖啡,而decorator认为是装饰者,因为喝咖啡可以不要调料,调料是可选的,装饰者是附着在上面的。

所谓装饰者就是动态的将新功能附加在对象上,在对象功能扩展方面,比继承更加的有弹性,装饰者也充分的体现出开闭原则。


二、设计方案

image.png

通过装饰者模式就有变化了,首先drink是抽象的,而单品咖啡可以独立出来,而decreator装饰者里面有各个调料。

说明:

Drink这个超类和前面基本一样;

Shortblack等单品咖啡的设计也和之前一样;

Decorator是装饰类,包含了被装饰的对象;

Decorator的cost费用要进行叠加,因为装饰者可以装饰,还可以继续装饰。

image.png

(1)有一份Milk+LongBlack【相当于是Milk装饰了

LongBlack】 Milk是装饰者,LongBlack是主体;

(2)使用 chocolate装饰了一份 Milk+LongBlack;

(3)使用 chocolate装饰 chocolate+LongBlack+Milk,层叠的进行装饰,当计算成本时要递归的计算,


三、代码

首先对照图

image.png

Drink 表示饮品,是抽象类,最主要抽象描述,因为饮品是个抽象的,所以是抽象方法,将计算成本的方法做成抽象方法,然后继承。

出现以下报错:

Package com.atguigu.chapter17.decorator.coffeebar.mycoffee

class Espresso extends coffee {

//使用主构造器

super.setDescription(“Espresso”)

super.setPrice(6.0f)

}

coffee 地方报错,因为在 component 和 concrete 之间做了一层缓冲层,因为从扩展性来说,将来可能咖啡店扩展了,除了有咖啡这种产品还有传统饮品,如果仅仅针对这个案例来说,可以不要,此处是为了扩展,意义并不大。

单品咖啡在装饰者设计模式中就是concrete:

packagecom. atguigu.chapter17.decorator .coffeebar.mycoffee

class Espresso extends Coffee {

super . setDescription("Espresso")

super . setPrice(6.0f)

}

decorator 是关键,是装饰者模式体现的价值:

class Decorator extends Drink {

private var obj: Drink =null

def this(obj: Drink) {

this.obj=obj

}

override def cost(): Float={

super . getprice()+obj.cost()

}

首先仍然继承 drink,object 是被装饰的, object可以是单品咖啡,也可以咖啡加调料的组合,计算成本实现了 COS 的方法,首先先得到自己的咖啡,然后递归的调用,因为是不停的装饰。

获取信息时,也要递归。chocolate 要继承 decorator,在巧克力里面放 drink,然后扩展它。放到体系里面,decorator 也是 drink 的子类,以此类推,牛奶也不停的往上继承。

使用时,直接调订单里面cost得到描述,因为无音咖啡继承coffee,而coffee又继承了 drink,订单一的价格就是三块钱,运行结果如下:

orde1 price: 3.0

order1 desc :Decaf 价格:3.0

如果需求是点一份longblack,并且加入两份巧克力代码如下:

Var order2:Drink=new Longblack

因为用装饰者模式,在定milk的时候,直接放进去即可,因为milk继承装饰者,所以就可以用decorator相应的方法,也把对象传给了decorator,decorator把对象交给了装饰者,一步一步传到decorator,

此时运行结果:

order2 price:7.0

order2 desc:Milk 价格:2.0&&LongBlack价格:5.0

假如还要再加两份巧克力和一份milk,结果如下:

order2 price:10.0

order2 desc:chocolate 价格:3.0&&Milk 价格:2.0&&LongBlack价格:5.0

如果还要再来一份咖啡,再包裹即可。当在目前基础上去增加新的饮品时,就不需要动整个类的体系结构了。

比如有一种新式的牛奶,复制一份即可,把名字或价格更改即可,价格也可以算出。如果单品咖啡再加一份,也是相同道理。如果需求特别复杂时就可以使用该设计模式。


四、举例

Java 中的 io 流里面有叫 fiilterinputstream,就是装饰者,inputstream就是被装饰者,

示意图如下:

image.png

如果想加入过滤的功能,继承之后然后把被装饰包裹,文件流也具有了过滤的功能,fiilterinputstream就是装饰者,而inputstream就是被装饰者。


五、总结

先提出需求,引起思考,需求是咖啡店有单品咖啡、调料,要求在扩展咖啡种类,用oo来计算不同种类咖啡的费用,可以单点可以组合。最原始的方法,会形成会出现类爆炸的情况。

image.png

第二种方案最大的问题就是将来会直接去修改代码,违反了ocp的原则,将来缺口会变得越来越大,应该尽量避免。

image.png

第三种方案是就是装饰者模式

image.png

在主体就是component,包装就是decorator,于是提出设计方案,先抽象出来一层,因为可能有很多子类,主体就是陶瓷或者衣服,主体叫component,由主体引申出concretecomponent,concrete是混凝土的意思,decorator就是装饰者,可以理解成各种调料。主体是最重要,装饰者是单品咖啡,装饰者就是动态的将新的功能附加在对象上,动态很重要,不需要改源代码,比继承更加的有弹性,充分利用递归的特性,也体现了开闭原则。先用装饰者设计模式设计方案如下:

image.png

相关文章
|
4月前
|
设计模式
二十三种设计模式:解密职责链模式-购物优惠活动的设计艺术
二十三种设计模式:解密职责链模式-购物优惠活动的设计艺术
|
30天前
|
设计模式
学会了这个设计模式,再也不是只会写if/else了
本文详细介绍了责任链设计模式(Chain of Responsibility Pattern),这是一种行为型设计模式,用于创建一个接收者对象的链,通过解耦请求的发送者和接收者,允许沿着链传递请求,直到某个接收者能够处理它。
学会了这个设计模式,再也不是只会写if/else了
|
4月前
|
设计模式 存储 机器学习/深度学习
掌握C++中介者模式:设计与应用全攻略
掌握C++中介者模式:设计与应用全攻略
92 0
|
4月前
|
设计模式 Java 数据库
二十三种设计模式全面解析-单例设计模式:解密全局独一无二的实例创造者
二十三种设计模式全面解析-单例设计模式:解密全局独一无二的实例创造者
|
4月前
|
设计模式 API 数据格式
二十三种设计模式全面解析-适配器模式:代码的奇迹之桥,连接你的世界!
二十三种设计模式全面解析-适配器模式:代码的奇迹之桥,连接你的世界!
|
4月前
|
设计模式
二十三种设计模式全面解析-建造者模式:构建完美对象的秘密武器
二十三种设计模式全面解析-建造者模式:构建完美对象的秘密武器
|
4月前
|
设计模式
二十三种设计模式全面解析-抽象工厂模式:创造无限可能的工厂之道
二十三种设计模式全面解析-抽象工厂模式:创造无限可能的工厂之道
|
设计模式 缓存 安全
2023-6-29-第十一式代理模式
2023-6-29-第十一式代理模式
64 0
|
设计模式 算法 前端开发
设计模式入门-工厂系列(保姆级教程)
设计模式入门-工厂系列(保姆级教程)
|
设计模式 JavaScript 前端开发