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

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

开发者学堂课程【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

相关文章
|
存储 Java 测试技术
JAVA-MAVEN初学者教程(配置、pom.xml、依赖管理等)
JAVA-MAVEN初学者教程(配置、pom.xml、依赖管理等)
2902 0
|
弹性计算 关系型数据库 数据库
手把手带你从自建 MySQL 迁移到云数据库,一步就能脱胎换骨
阿里云瑶池数据库来开课啦!自建数据库迁移至云数据库 RDS原来只要一步操作就能搞定!
|
机器学习/深度学习 Linux 开发者
Python必备工具:pip的安装与管理
Python必备工具:pip的安装与管理
1575 0
|
Java 关系型数据库 MySQL
【项目】手把手带你用 SpringBoot、Uniapp、MySql 开发一个简单的活动报名项目
【项目】手把手带你用 SpringBoot、Uniapp、MySql 开发一个简单的活动报名项目
906 1
|
网络协议 算法 Linux
TCP是如何进行拥塞控制的?
TCP是如何进行拥塞控制的?
525 1
|
存储 C语言
C语言程序设计——ASCII码
C语言程序设计——ASCII码
基本时间单位 | 带你读《5G 空口设计与实践进阶 》之十五
为提供精确、一致的时间度量,NR 定义了最小时间单位 Tc。
基本时间单位 | 带你读《5G 空口设计与实践进阶 》之十五
|
前端开发 JavaScript 数据库
uniapp项目实战系列(1):导入数据库,启动后端服务,开启代码托管
uniapp项目实战系列(1):导入数据库,启动后端服务,开启代码托管
1640 2
|
存储 缓存 数据安全/隐私保护
【uni-app】使用uni-app实现简单的登录注册功能
前言 大家好,今天和大家分享一下如何在uni-app中实现简单的登录注册功能。 首先你需要掌握一下知识点:
error: Two output files share the same path but have different contents: node_modules\.vite\..xxx.js
error: Two output files share the same path but have different contents: node_modules\.vite\..xxx.js
1018 0
error: Two output files share the same path but have different contents: node_modules\.vite\..xxx.js