吃透设计模式第六篇-装饰者模式
设计模式的重要性对于程序员来说,相当于盾牌对于美国队长,暴风战斧相对于雷神,内裤对于绿巨人(绿巨人最强武器,手动狗头)来说,是必不可少的。
在此,特别总结下23钟设计模式:
- 创建型模式:单例模式、抽象工厂模式、原型模式、建造者模式、工厂模式。
- 结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
- 行为型模式:模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、 解释器模式(Interpreter 模式)、状态模式、策略模式、职责链模式(责任链模式)。
本人将会以专栏形式详细介绍下每种设计模式,文章代码使用java语言,希望能够帮助读者打造一柄编码前行路上的神兵利器。
本文主要针对设计模式的第六种,装饰者模式进行详细介绍
1.首先看一个需求订购奶茶
- 奶茶的种类:焦糖奶茶,鲜芋奶茶,港式奶茶等
- 配料:红豆,珍珠,椰果等
- 要求在增加新的奶茶种类和新的配料时候有良好的拓展性
- 计算不同奶茶的费用:可以单点,也可以添加多种配料
2.对于需求的初步分析,给出方案一
3. 方案一分析
- MilkTea是一个抽象类,表示奶茶
- description为描述
- cost()计算价格,是MilkTea的一个抽象方法
- GangshiMikeTea(港式),JiaotangMikeTea(焦糖),XianyuMikeTea(鲜芋)为单品奶茶
- JiaotangMikeTea&&Zhenzhu,GangshiMikeTea&&RedBean为单品加配料,这个组合有很多种
问题:这样设计,会有很多类,当我们增加一个单品咖啡,或者一个新的调料,类的数量就会倍增,就会出现类爆炸
4.方案二解决奶茶问题(方案一的改进)
前面分析到方案 一 因为奶茶单品+配料组合会造成类的倍增,因此可以做改进,将配料内置到 MilkTea 类,这样就不会造成类数量过多。从而提高项目的维护性(如图)
说明: redBean,coconut,zhenzhu可以设计为 Boolean,表示是否要添加相应的配料
5. 方案二的分析
- 方案二可以控制类的数量,不至于造成很多的类
- 在增加配料时候,涉及到的改动,代码维护量很大
- 用户需要多份配料可以更改hasXXX方法放回int表示份数
- 违反了开闭原则
- 考虑使用装饰者模式
6. 装饰者模式基本介绍
- 装饰者模式:动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性,装饰者模式也体现了开闭原则(ocp)
- 这里提到的动态的将新功能附加到对象和 ocp 原则,读者可以从后续的代码演示中理解
7. 装饰者模式原理
- 装饰者模式就像打包一个快递 主体:比如:陶瓷、衣服 (Component) // 被装饰者 包装:比如:报纸填充、塑料泡沫、纸板、木板(Decorator)
- Component 主体:比如类似前面的 MilkTea
- ConcreteComponent 和 Decorator,ConcreteComponent:具体的主体,比如前面的各个单品奶茶
- Decorator: 装饰者,比如各配料
在如图的 Component 与 ConcreteComponent 之间,如果 ConcreteComponent 类很多,还可以设计一个缓冲层,将共有的部分提取出来,抽象层一个类。
8. 装饰者模式解决奶茶订单
装饰者模式下的订单:2 份珍珠+一份红豆的港式奶茶
说明:RedBeans包含了GangshiMilkTea
中层的Zhenzhu包含了(GangshiMilkTea+RedBeans)
最外层的Zhenzhu包含了(GangshiMilkTea+RedBeans+Zhenzhu)
9.装饰者模式奶茶订单项目应用实例
/*** 奶茶*/
public abstract class MilkTea {public String des; // 描述private float price = 0.0f;public String getDes() {return des;}public void setDes(String des) {this.des = des;}public float getPrice() {return price;}public void setPrice(float price) {this.price = price;}//计算费用的抽象方法public abstract float cost();
}
/*** Coco奶茶*/
public class Coco extends MilkTea {@Overridepublic float cost() {return super.getPrice();}
}
/*** 港式奶茶*/
public class GangshiMilkTea extends Coco{public GangshiMilkTea() {setDes("港式奶茶...........");setPrice(10.0f);}
}
/*** 焦糖奶茶*/
public class JiaotangMilkTea extends Coco{public JiaotangMilkTea() {setDes("焦糖奶茶...........");setPrice(12.0f);}
}
/*** 鲜芋奶茶*/
public class XianyuMilkTea extends Coco{public XianyuMilkTea() {setDes("鲜芋奶茶...........");setPrice(13.0f);}
}
/*** 装饰器*/
public class Decorator extends MilkTea {private MilkTea milkTea;public Decorator(MilkTea milkTea) {this.milkTea = milkTea;}@Overridepublic float cost() {return super.getPrice()+milkTea.cost();}
}
/*** 配料红豆*/
public class RedBeans extends Decorator{public RedBeans(MilkTea milkTea) {super(milkTea);setDes("加红豆");setPrice(2.0f);}
}
/*** 配料椰果*/
public class Coconut extends Decorator{public Coconut(MilkTea milkTea) {super(milkTea);setDes("加椰果");setPrice(3.0f);}
}
/*** 配料珍珠*/
public class Zhenzhu extends Decorator{public Zhenzhu(MilkTea milkTea) {super(milkTea);setDes("加珍珠");setPrice(4.0f);}
}
/*** 下单*/
public class OrderClient {public static void main(String[] args) {//1.点一杯港式奶茶MilkTea milkTea = new GangshiMilkTea();System.out.println("港式奶茶的费用: "+milkTea.cost());System.out.println("港式奶茶的描述: "+milkTea.getDes());//加红豆milkTea = new RedBeans(milkTea);System.out.println("港式奶茶加红豆的费用: "+milkTea.cost());System.out.println("港式奶茶加红豆的描述: "+milkTea.getDes());//加椰果milkTea = new Coconut(milkTea);System.out.println("港式奶茶加红豆再加椰果的费用: "+milkTea.cost());System.out.println("港式奶茶加红豆再加椰果的描述: "+milkTea.getDes());//加珍珠milkTea = new Zhenzhu(milkTea);System.out.println("港式奶茶加红豆再加椰果再加珍珠的费用: "+milkTea.cost());System.out.println("港式奶茶加红豆再加椰果再加珍珠的描述: "+milkTea.getDes());//加珍珠milkTea = new Zhenzhu(milkTea);System.out.println("港式奶茶加红豆再加椰果再加2份珍珠的费用: "+milkTea.cost());System.out.println("港式奶茶加红豆再加椰果再加2份珍珠的描述: "+milkTea.getDes());}
}
最终的结果:
10. 装饰者模式在 JDK 应用的源码分析
Java 的 IO 结构,FilterInputStream 就是一个装饰者
上图引用自JAVA IO流结构图概览
- InputStream 是抽象类, 类似我们前面讲的 MilkTea
- FileInputStream 是 InputStream 子类,类似我们前面的 GangshiMilkTea, JiaotangMilkTea
- FilterInputStream 是 InputStream 子类:类似我们前面 的 Decorator 修饰者
- DataInputStream 是 FilterInputStream 子类,具体的修饰者,类似前面的 RedBeans, Zhenzhu等
- FilterInputStream 类 有 protected volatile InputStream in; 即含被装饰者
- 分析得出在 jdk 的 io 体系中,就是使用装饰者模式
吃透设计模式第六篇-装饰者模式相关推荐
- 肝一肝设计模式【六】-- 装饰器模式
系列文章目录 肝一肝设计模式[一]-- 单例模式 传送门 肝一肝设计模式[二]-- 工厂模式 传送门 肝一肝设计模式[三]-- 原型模式 传送门 肝一肝设计模式[四]-- 建造者模式 传送门 肝一肝设 ...
- 设计模式第三篇-装饰者模式
一.引言 先看一个开发问题,很多人都玩过英雄联盟这款游戏:里面有各种英雄,每个英雄都有各自的技能(一般是4个主动技能),每升一级可以升级一个技能,但是可升级的技能不固定.我们需要通过技能状态来计算伤害 ...
- Android Ap 开发 设计模式第六篇:原型模式
Prototype Pattern 名称由来 不是利用类来产生实例对象,而是从一个对象实例产生出另一个新的对象实例 ,根据被视为原型的对象实例 ,建立起的另一个新的对象实例就称为原型模式(Ptotot ...
- Java进阶专题(八) 设计模式之适配器模式、装饰者模式、观察者模式
本章节将介绍:三个设计模式,适配器模式.装饰者模式和观察者模式.通过学习适配器模式,可以优雅的解决代码功能的兼容问题.另外有重构需求的人群一定需要掌握装饰者模式.本章节参考资料书籍<Spring ...
- php设计模式课程---7、装饰器模式如何使用
php设计模式课程---7.装饰器模式如何使用 一.总结 一句话总结: 装饰器的核心是获取了文章类整个类,而不是获取了文章内容,有了这个文章类,我想给你加多少装饰就给你加多少装饰(将文章这个类封装进去 ...
- 设计模式(三)—— 装饰者模式
由于之前看的容易忘记,因此特记录下来,以便学习总结与更好理解,该系列博文也是第一次记录,所有有好多不完善之处请见谅与留言指出,如果有幸大家看到该博文,希望报以参考目的看浏览,如有错误之处,谢谢大家指出 ...
- 孙猴子装饰七十二变篇--装饰器模式C++实现
人物: WuKong 悟空 Heart_Hole 菩提老祖学艺处,学会七十二变等 West_Sea 海,找到金箍棒 装饰器模式 悟空到了菩提老祖这个类,被装饰了七十二变 到了大海,被装饰了金箍棒. 设 ...
- 设计模式笔记十:装饰器模式
原文:http://www.runoob.com/design-pattern/ (大部分摘抄) 少许个人理解,如有错误请指出.欢迎一起讨论. 装饰器模式(Decorator Pattern) 允许向 ...
- C++设计模式详解之装饰者模式解析
装饰者模式的概念 装饰者模式指的是动态的将责任附加到对象上,想要扩展其功能,装饰者提供有别于继承的另一种选择.(参考<Head First 设计模式>) 个人理解:装饰者就是一种类包类 就 ...
最新文章
- React和vue的差异和相似地方
- commit your changes or stash them before you can merge
- 180508 - 解决有关VIVO的2018-04-01安全补丁导致的APP闪退问题
- zookeeper - watcher(9)
- 修改mysql表的itemId字段为自增长SQL语句
- 使用MVC模式制作游戏-教程和简介
- 【算法实践】搜狗信息流推荐算法交流.pdf(附下载链接)
- 如何将cocos2d-x项目打包成一个.exe
- chinese-ocr自然场景下不定长文字识别(ctpn + densenet)
- Simulink模块之VCO(压控振荡器)
- ROC曲线及AUC值
- [Ubuntu] fg、bg让你的进程在前后台之间切换
- 激光雕刻机的位图-GCode转换方法实践
- 锐起无盘工作站网卡配置
- opencv 二值化处理
- python实现SG滤波
- steam linux不能运行,ubuntu 16.04下不能启动Steam的解决方法
- 教程:如何制作一个可控制的人体骨骼模型
- 大厂程序员都会的分布式RPC框架,直接无私打包分享,手慢无
- 数字IC设计的基本流程和主流EDA工具
热门文章
- win10更新双系统启动选项消失得解决方案
- java format用法_Java中String 的 format用法
- [139]python selenium之模拟键盘操作
- android主题商店,主题商店免费版
- win10英雄联盟登录服务器未响应,win10系统lol英雄联盟登录服务器未响应的恢复技巧...
- Excel如何按照指定顺序排列
- Python数据可视化 Pyecharts 制作 Boxplot 箱线图
- JAVA高考加油_高考祝福语给高三学生加油打气的话
- 斐波那契(黄金分割)查找
- wpf怎么让Textbox只能输入数字?