Head First 设计模式 —— 03. 装饰器 (Decorator) 模式
思考题
有如下类设计:
如果牛奶的价钱上扬,怎么办?新增一种焦糖调料风味时,怎么办?
造成这种维护上的困难,违反了我们之前提过的哪种设计原则? P82
- 取出并封装变化的部分,让其他部分不收影响
- 多用组合,少用继承
思考题
请为下面类的 cost() 方法书写代码。 P83
抽象类:Beverage
public class Beverage {
public double cost() {
double totalCost = 0.0;
if (hasMilk()) {
totalCost += milkCost;
}
if (hasSoy()) {
totalCost += soyCost;
}
if (hasMocha()) {
totalCost += mochaCost;
}
if (hasWhip()) {
totalCost += whipCost;
}
return totalCost;
}
}
具体类:DarkRoast
public class DarkRoast extends Beverage {
public DarkRoast() {
description = "Most Excellent Dark Roast";
}
public double cost() {
return baseCost + super.cost();
}
}
思考题
当哪些需求或因素改变时会影响这个设计? P84
- 调料价钱的改变会使我们改变现有代码
- 一旦出现新的调料,我们就需要加上新的方法,并改变超类中的 cost() 方法
- 以后可能会开发出新饮料。对这些饮料而言(例如:冰茶),某些调料可能并不适合,但是在这个设计方式中,Tea (茶)子类仍然将继承那些不适合的方法,例如:hasWhip() (加奶泡)
- 万一顾客想要双倍摩卡或咖啡,怎么办?
- 调料价钱随着具体饮料而改变
- 饮料基础价钱随着大中小被的不同而改变
设计原则
- 开闭原则:类应该对扩展开放,对修改关闭
P86
- 策略模式、观察者模式和装饰器模式均遵循开闭原则
P105
- 策略模式、观察者模式和装饰器模式均遵循开闭原则
装饰器模式
动态地将责任附加到对象上,而不改变其原有代码。若扩展功能,装饰器提供了比继承更优弹性的替代方案。 P91
特点
- 装饰类和被装饰类有相同的超类型
P90
- 装饰类可以在所委托的被装饰类的行为之前(或之后),加上自己的行为,以达到特定的目的
P90
- 可以透明地插入装饰器,使用时甚至不需要知道是在和装饰器交互
P104
- 适合用来建立有弹性的设计,维持开闭原则
P104
缺点
- 存在大量小类,使用时将会增加代码复杂度
P101
P104
- 使用时依赖某种特殊类型,然后忽然导入装饰器,却又没有周详地考虑一切
P104
思考题
我们在星巴兹的朋友决定开始在菜单上加上咖啡的容量大小,供顾客可以选择小贝(tall)、中杯(grande)、大杯(venti)。星巴兹认为这是任何咖啡都必须具备的,所以在 Beverage 类中加上了 getSize() 与 setSize() 。他们也希望调料根据咖啡容量收费,例如:小中大杯的咖啡加上豆浆,分别加收 0.10、0.15、0.20 美金。
如何改变装饰者类应对这一的需求? P99
public class Soy extends CondimentDecorator {
Beverage beverage;
public Soy(Beverage beverage) {
this.beverage = beverage;
}
public int getSize() {
return beverage.getSize();
}
public void setSize(int size) {
beverage.setSize(size);
}
public String getDescription() {
return beverage.getDescription() + ", Soy";
}
public double cost() {
double soyCost = 0.0;
switch (getSize()) {
case TALL:
soyCost = 0.10;
break;
case GRANDE:
soyCost = 0.15;
break;
case VENTI:
soyCost = 0.20;
break;
default:
soyCost = 0.0;
}
return beverage.cost() + soyCost;
}
}
所思所想
- 装饰器模式使用了继承(或实现接口)的方式,所以超类型增加方法时,所有子类都需要改变,设计时要充分考虑
- 总感觉装饰器模式很熟悉,看了 java-design-patterns/decorator 后,发现装饰器模式的思想平常都是运用在 AOP 中实现的 (最后学了代理模式发现原来是动态代理模式)
本文首发于公众号:满赋诸机(点击查看原文) 开源在 GitHub :reading-notes/head-first-design-patterns
Head First 设计模式 —— 03. 装饰器 (Decorator) 模式的更多相关文章
- 装饰器(Decorator)模式
public interface IDoThings { public void doSomeThing(); } public class DoThings implements IDoThings ...
- java设计模式03装饰者者模式
动态地给一个对象添加一些额外的职责.就增加功能来说, Decorator模式相比生成子类更为灵活.该模式以对客 户端透明的方式扩展对象的功能. (1)在不影响其他对象的情况下,以动态.透明的方式给单个 ...
- 设计模式:装饰器(Decorator)模式
设计模式:装饰器(Decorator)模式 一.前言 装饰器模式也是一种非常重要的模式,在Java以及程序设计中占据着重要的地位.比如Java的数据流处理,我们可能看到数据流经过不同的类的包装和 ...
- python 设计模式之装饰器模式 Decorator Pattern
#写在前面 已经有一个礼拜多没写博客了,因为沉醉在了<妙味>这部小说里,里面讲的是一个厨师苏秒的故事.现实中大部分人不会有她的天分.我喜欢她的性格:总是想着去解决问题,好像从来没有怨天尤人 ...
- PHP设计模式之装饰器模式(Decorator)
PHP设计模式之装饰器模式(Decorator) 装饰器模式 装饰器模式允许我们给一个类添加新的功能,而不改变其原有的结构.这种类型的类属于结构类,它是作为现有的类的一个包装 装饰器模式的应用场景 当 ...
- Java设计模式07:常用设计模式之装饰器模式(结构型模式)
1. Java之装饰器模式(Decorator Pattern) (1)概述: 装饰模式在Java种使用也很广泛,比如我们在重新定义按钮.对话框等时候,实际上已经在使用装饰模式了.在不必改变原 ...
- JS 设计模式九 -- 装饰器模式
概念 装饰者(decorator)模式能够在不改变对象自身的基础上,动态的给某个对象添加额外的职责,不会影响原有接口的功能. 模拟传统面向对象语言的装饰者模式 //原始的飞机类 var Plane = ...
- 设计模式之装饰(Decorator)模式
设计模式之装饰(Decorator)模式 (一)什么是装饰(Decorator)模式 装饰模式,又称为包装模式,它以对客户端透明的方式扩张对象的功能,是继承关系的替代方案之一. 装饰模式可以在不使用创 ...
- python设计模式之装饰器详解(三)
python的装饰器使用是python语言一个非常重要的部分,装饰器是程序设计模式中装饰模式的具体化,python提供了特殊的语法糖可以非常方便的实现装饰模式. 系列文章 python设计模式之单例模 ...
随机推荐
- SpringCloud Alibaba学习笔记
目录 目录 目录 导学 为什么学 学习目标 进阶目标 思路 Spring Cloud Alibaba的重要组件 环境搭建 Spring Boot必知必会 Spring Boot特性 编写第一个Spri ...
- 团队作业3_需求改进&系统设计
一.需求&原型改进 1.需求改进: (1)发现问题:通过发布问卷调查及收集整理的形式发现用户的新需求: (2)修改需求:考虑新增提醒用户未完成事件的功能. 附:用户调查问卷(如下) 调研途 ...
- element ui的el-radio踩坑
1.html 1 <div class="listPeopleDetail"> 2 <div class="item" v-for=" ...
- AcWing 392. 会合
一个思路不难,但是实现起来有点毒瘤的题. 显然题目给出的是基环树(内向树)森林. 把每一个基环抠出来. 大力分类讨论: 若 \(a, b\) 不在一个联通量里,显然是 \(-1, -1\) 若 \(a ...
- cocosCreator微信小游戏排行榜思路
cocosCreator制作微信小游戏排行榜实现方案: 游戏认知:项目分为主域和子域,主域就是游戏主程部分,子域为单独处理微信排行榜公共域数据的. 游戏主域里创建一个节点,添加WXSubContext ...
- I/O-外部设备
目录 输入设备 输出设备 显示器 阴极射线管(CRT)显示器 字符显示器 图形显示器 图像显示器 打印机 小结 外存储器 磁盘存储器 磁盘设备的组成 存储区域 硬盘存储器 磁盘的性能指标 磁盘地址 硬 ...
- SpringBoot + Layui +Mybatis-plus实现简单后台管理系统(内置安全过滤器)
1. 简介 layui(谐音:类UI)是一款采用自身模块规范编写的前端UI框架,遵循原生HTML/CSS/JS的书写与组织形式,门槛极低,拿来即用.其外在极简,却又不失饱满的内在,体积轻盈,组件丰 ...
- 微信小程序自动化,记录趟过的坑!
项目思想:关键字+数据驱动混合测试 基于Android-微信小程序自动化的关键是:webview的切换 对于微信App来说如何从NATIVE切换到webview的过程 测试版本信息 1.微信版本:7. ...
- 浅谈JAVA代码优化
JAVA代码的优化分为两个方面: 一.减小代码的体积.二.提高代码的执行效率. ============================================================ ...
- Thymeleaf的th
th:action 定义后台控制器路径,类似<form>标签的action属性. <form id="login-form" th:action="@{ ...