第 17 章 设计模式(3 装饰者模式)
一、提出需求
咖啡馆订单系统项目(咖啡馆):
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. 这种设计方式时,会有很多的类,并且当增加一个新的单品咖啡或者调料时,类的数量就会倍增(类爆炸)。
2、方案二:比较好点的方案
前面分析到方案一,因为咖啡单品+调料组合会造成类的倍增,因此可以做改进,将调料内置到Drink类,这样
就不会造成类数量过多。从而提高项目的维护性。
方案设计如下图:
说明: milk,soy,choclate 可以设计为Boolean,表示是否要添加相应的调料。
方案二的问题分析
1. 方案2可以控制类的数量,不至于造成过多的类;
2. 在增删调料种类时,代码维护量仍然很大;
3. 考虑到添加多份调料时,可以将Boolean改成Int。
三、装饰者模式原理
1、方案设计图
2、针对上面的图说明
1. 装饰者模式就像打包一个快递:主体:比如:陶瓷、衣服 (Component)包装:比如:报纸填充、塑料泡沫、纸板、木板(Decorator)
2. Component主体:比如类似前面的Drink;
3. ConcreteComponent和DecoratorConcreteComponent:具体的主体,比如前面的各个单品咖啡Decorator: 装饰者,比如各调料.
4. 在上面的图中Component与ConcreteComponent之间,如果ConcreteComponent类很多,还可以设计一个缓冲层,
将共有的部分提取出来,抽象层一个类。
四、装饰者模式定义
1. 装饰者模式:动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性,装饰者模式也体现了
开闭原则(ocp);
2. 这里提到的动态的将新功能附加到对象和ocp原则,接下来会在应用实例上会以代码的形式体现。
五、用装饰者模式重新设计方案
1、方案设计图
2、方案说明
1. Drink这个超类和前面基本一样;
2. ShortBlack等单品咖啡的设计也和前面一样;
3. Decorator是一个装饰类,含一个被装饰的对象(Drink obj);
4. Decorator的cost 进行费用的叠加,递归计算出价格。
3、订单
装饰者模式下的订单:2份巧克力+一份牛奶的LongBlack
订单说明:
1. Milk包含了LongBlack;
2. 一份Chocolate包含了(Milk+LongBlack);
3. 一份Chocolate包含了(Chocolate+Milk+LongBlack);
4. 这样不管是什么形式的单品咖啡+调料组合,通过递归方式可以方便的组合和维护。
订单分析
1. 有一份 Milk + LongBlack【milk装饰LongBlack】;
2. 使用一份Chocolate装饰【一份 Milk + LongBlack 】;
3. 使用一份chocolate装饰【chocolate+milk+longBlack】;
4. 当计算cost要递归的计算。
五、装饰者模式咖啡订单项目应用实例代码
1、代码结构图
2、示例代码
================================abstract class Drink 超类================================
package com.lj.akka.decoratormode.coffeebar
/*** @author Administrator* @create 2020-03-28*/
abstract class Drink {// coffee描述private var _description: String = _// _description的setter与getter方法def description: String = _descriptiondef description_=(value: String): Unit = {_description = value}// coffee价格private var _price: Float = _// _price的setter与getter方法def price: Float = _pricedef price_=(value: Float): Unit = {_price = value}def cost(): Float
}
==================================class Coffee extends Drink=================================
package com.lj.akka.decoratormode.coffeebar.differentcoffee
import com.lj.akka.decoratormode.coffeebar.Drink
/*** @author Administrator* @create 2020-03-28*/
class Coffee extends Drink {override def cost(): Float = {super.price}
}
==================================class DeCaf extends Coffee=================================
// 说明:其它种类的咖啡,它这个一样的写法都是集成Coffee类,并使用主构造器完成价格和名称描述
package com.lj.akka.decoratormode.coffeebar.differentcoffee
/*** @author Administrator* @create 2020-03-28*/
class DeCaf extends Coffee {// 使用主构造器super.description_=("DeCaf Coffee")super.price_=(10.0f)
}
===============================class Decorator extends Drink==============================package com.lj.akka.decoratormode.coffeebar.coffeedecorator
import com.lj.akka.decoratormode.coffeebar.Drink
/*** @author Administrator* @create 2020-03-28*/
class Decorator extends Drink{private var drink: Drink = nulldef this(drink: Drink) {thisthis.drink = drink}override def cost(): Float = {super.price + drink.cost()}// 获取信息是也需要递归获取override def description: String = {super.description + " && " + drink.description}
}
===============class Chocolate(drink: Drink) extends Decorator(drink)===============
// 其它的添加的配料写法都一样
package com.lj.akka.decoratormode.coffeebar.coffeedecorator
import com.lj.akka.decoratormode.coffeebar.Drink
/*** @author Administrator* @create 2020-03-28*/
class Chocolate(drink: Drink) extends Decorator(drink) {super.description_=("Chocolate")super.price_=(5f)
}
============================咖啡点单:object CoffeeBar============================
package com.lj.akka.decoratormode
import com.lj.akka.decoratormode.coffeebar.Drink
import com.lj.akka.decoratormode.coffeebar.coffeedecorator.{Chocolate, Milk}
import com.lj.akka.decoratormode.coffeebar.differentcoffee.{DeCaf, LongBlack}
/*** @author Administrator* @create 2020-03-28*/
object CoffeeBar {def main(args: Array[String]): Unit = {val order01: Drink = new DeCafval order01_name = order01.descriptionval order01_price = order01.cost()// 001顾客点的是DeCaf Coffee,价格10.0RMB.println(s"001顾客点的是${order01_name},合计${order01_price}RMB.")var order02: Drink = new LongBlackorder02 = new Milk(order02)order02 = new Chocolate(order02)order02 = new Milk(order02)val order02_name = order02.descriptionval order02_price = order02.cost()// 002顾客点的是Chocolate && Chocolate && Chocolate && LongBlack Coffee,合计26.0RMB.println(s"002顾客点的是${order02_name},合计${order02_price}RMB.")}
}
小结:从上面代码可以看出装饰者模式在代码维护上更加的复合OCP原则,使代码更优雅。
3、Java中装饰者模式的经典使用
Java的IO结构,FilterInputStream就是一个装饰者
对以前的知识回顾,加深基础知识!
学习来自:北京尚硅谷韩顺平老师—尚硅谷大数据技术之Scala
每天进步一点点,也许某一天你也会变得那么渺小!!!
第 17 章 设计模式(3 装饰者模式)相关推荐
- 设计模式学习----装饰器模式
这两天本来是自在学习java collection Framework的Fail Fast底层机制,看到核心的部分时,突然意识到设计模式的问题,上大学到现在我还没有真正理解过设计模式的概念,于是用了大 ...
- 设计模式之装饰者模式--钢铁侠的形成
前言 本文主要讲述java常见设计模式之装饰者模式,文中使用通俗易懂的案例,使你更好的学习本章知识点并理解原理,做到有道无术. 一.什么是装饰者模式 装饰者模式是23种设计模式中结构型模式的一种,它的 ...
- 设计模式之装饰器模式详解
设计模式之装饰器模式详解 文章目录 设计模式之装饰器模式详解 一.什么是装饰器模式 二.装饰器模式的角色组成 三.装饰器模式通用写法示例 四.装饰器模式业务中的应用举例 五.装饰器模式优缺点 一.什么 ...
- Java设计模式(装饰者模式-组合模式-外观模式-享元模式)
Java设计模式Ⅳ 1.装饰者模式 1.1 装饰者模式概述 1.2 代码理解 2.组合模式 2.1 组合模式概述 2.2 代码理解 3.外观模式 3.1 外观模式概述 3.2 代码理解 4.享元模式 ...
- 前端也要学系列:设计模式之装饰者模式
什么是装饰者模式 今天我们来讲另外一个非常实用的设计模式:装饰者模式.这个名字听上去有些莫名其妙,不着急,我们先来记住它的一个别名:包装器模式. 我们记着这两个名字来开始今天的文章. 首先还是上< ...
- 设计模式 之 装饰者模式
2019独角兽企业重金招聘Python工程师标准>>> 设计模式 之 装饰者模式 装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能.它是通过创建一个包装对 ...
- 【设计模式】装饰者模式 ( 概念 | 适用场景 | 优缺点 | 与继承对比 | 定义流程 | 运行机制 | 案例分析 )
文章目录 I . 装饰者模式概念 II . 装饰者模式适用场景 III . 装饰者模式优缺点 IV . 装饰者模式与继承对比 V . 装饰者模式相关设计模式 VI . 装饰者模式四个相关类 VII . ...
- 【设计模式】装饰器模式的使用
问题来源 我们在进行软件系统设计的时候,有一些业务(如下图,一些通用的非功能性需求)是多个模块都需要的,是跨越模块的.把它们放到什么地方呢? 最简单的办法就是把这些通用模块的接口写好,让程序员在实现业 ...
- C#设计模式(9)——装饰者模式(Decorator Pattern)
一.引言 在软件开发中,我们经常想要对一类对象添加不同的功能,例如要给手机添加贴膜,手机挂件,手机外壳等,如果此时利用继承来实现的话,就需要定义无数的类,如StickerPhone(贴膜是手机类).A ...
- go设计模式之装饰器模式
go设计模式之装饰器模式 再写这篇文章时,我已经看了很多其他人发表的类似文章,大概看了这么多吧. 亓斌的设计模式-装饰者模式(Go语言描述) jeanphorn的Golang设计模式之装饰模式 七八月 ...
最新文章
- linux什么命令只显示ip,linux ip命令
- 科普:教你如何看懂 JavaGC 日志
- 用户画像从0到100的构建思路
- pc显示器分辨率 前端_五款高性价比PC显示器推荐 499元起
- zabbix db partition
- BugkuCTF-MISC题宽带信息泄露
- python getattr函数_Python中的getattr()函数详解
- Mysql 数据库默认值选 ‘‘“ 、Null和Empty String的区别
- HDU2092 整数解【暴力+韦达定理】
- [python] 解决OSError: Address already in use
- LAMMPS分子动力学模拟技术与应用 第一性原理计算方法及应用
- 数据库知识整理 - 并发控制(封锁、两段锁协议、意向锁)
- android 触摸 事件,Android触屏事件和MotionEvent详解
- 使用JavaScript获取当前时间方法(AM、PM)
- Java程序员月薪达到三万,需要技术水平达到什么程度?(文末送书)
- 手机html点击按钮复制,网页文字无法复制?按下手机这个键即可复制!网友:厉害了...
- 清华大学计算机崔勇,崔勇 简历 - 名人简历
- placement new 讲解
- 【java】环境变量安装
- 今天是2012年9月20日