设计模式的重要性对于程序员来说,相当于盾牌对于美国队长,暴风战斧相对于雷神,内裤对于绿巨人(绿巨人最强武器,手动狗头)来说,是必不可少的。

在此,特别总结下23钟设计模式:

  • 创建型模式:单例模式、抽象工厂模式、原型模式、建造者模式、工厂模式。
  • 结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
  • 行为型模式:模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、 解释器模式(Interpreter 模式)、状态模式、策略模式、职责链模式(责任链模式)。

本人将会以专栏形式详细介绍下每种设计模式,文章代码使用java语言,希望能够帮助读者打造一柄编码前行路上的神兵利器。

本文主要针对设计模式的第六种,装饰者模式进行详细介绍

1.首先看一个需求订购奶茶

  1. 奶茶的种类:焦糖奶茶,鲜芋奶茶,港式奶茶等
  2. 配料:红豆,珍珠,椰果等
  3. 要求在增加新的奶茶种类和新的配料时候有良好的拓展性
  4. 计算不同奶茶的费用:可以单点,也可以添加多种配料

2.对于需求的初步分析,给出方案一

3. 方案一分析

  1. MilkTea是一个抽象类,表示奶茶
  2. description为描述
  3. cost()计算价格,是MilkTea的一个抽象方法
  4. GangshiMikeTea(港式),JiaotangMikeTea(焦糖),XianyuMikeTea(鲜芋)为单品奶茶
  5. JiaotangMikeTea&&Zhenzhu,GangshiMikeTea&&RedBean为单品加配料,这个组合有很多种

问题:这样设计,会有很多类,当我们增加一个单品咖啡,或者一个新的调料,类的数量就会倍增,就会出现类爆炸

4.方案二解决奶茶问题(方案一的改进)

前面分析到方案 一 因为奶茶单品+配料组合会造成类的倍增,因此可以做改进,将配料内置到 MilkTea 类,这样就不会造成类数量过多。从而提高项目的维护性(如图)


说明: redBean,coconut,zhenzhu可以设计为 Boolean,表示是否要添加相应的配料

5. 方案二的分析

  1. 方案二可以控制类的数量,不至于造成很多的类
  2. 在增加配料时候,涉及到的改动,代码维护量很大
  3. 用户需要多份配料可以更改hasXXX方法放回int表示份数
  4. 违反了开闭原则
  5. 考虑使用装饰者模式

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 体系中,就是使用装饰者模式

吃透设计模式第六篇-装饰者模式相关推荐

  1. 肝一肝设计模式【六】-- 装饰器模式

    系列文章目录 肝一肝设计模式[一]-- 单例模式 传送门 肝一肝设计模式[二]-- 工厂模式 传送门 肝一肝设计模式[三]-- 原型模式 传送门 肝一肝设计模式[四]-- 建造者模式 传送门 肝一肝设 ...

  2. 设计模式第三篇-装饰者模式

    一.引言 先看一个开发问题,很多人都玩过英雄联盟这款游戏:里面有各种英雄,每个英雄都有各自的技能(一般是4个主动技能),每升一级可以升级一个技能,但是可升级的技能不固定.我们需要通过技能状态来计算伤害 ...

  3. Android Ap 开发 设计模式第六篇:原型模式

    Prototype Pattern 名称由来 不是利用类来产生实例对象,而是从一个对象实例产生出另一个新的对象实例 ,根据被视为原型的对象实例 ,建立起的另一个新的对象实例就称为原型模式(Ptotot ...

  4. Java进阶专题(八) 设计模式之适配器模式、装饰者模式、观察者模式

    本章节将介绍:三个设计模式,适配器模式.装饰者模式和观察者模式.通过学习适配器模式,可以优雅的解决代码功能的兼容问题.另外有重构需求的人群一定需要掌握装饰者模式.本章节参考资料书籍<Spring ...

  5. php设计模式课程---7、装饰器模式如何使用

    php设计模式课程---7.装饰器模式如何使用 一.总结 一句话总结: 装饰器的核心是获取了文章类整个类,而不是获取了文章内容,有了这个文章类,我想给你加多少装饰就给你加多少装饰(将文章这个类封装进去 ...

  6. 设计模式(三)—— 装饰者模式

    由于之前看的容易忘记,因此特记录下来,以便学习总结与更好理解,该系列博文也是第一次记录,所有有好多不完善之处请见谅与留言指出,如果有幸大家看到该博文,希望报以参考目的看浏览,如有错误之处,谢谢大家指出 ...

  7. 孙猴子装饰七十二变篇--装饰器模式C++实现

    人物: WuKong 悟空 Heart_Hole 菩提老祖学艺处,学会七十二变等 West_Sea 海,找到金箍棒 装饰器模式 悟空到了菩提老祖这个类,被装饰了七十二变 到了大海,被装饰了金箍棒. 设 ...

  8. 设计模式笔记十:装饰器模式

    原文:http://www.runoob.com/design-pattern/ (大部分摘抄) 少许个人理解,如有错误请指出.欢迎一起讨论. 装饰器模式(Decorator Pattern) 允许向 ...

  9. C++设计模式详解之装饰者模式解析

    装饰者模式的概念 装饰者模式指的是动态的将责任附加到对象上,想要扩展其功能,装饰者提供有别于继承的另一种选择.(参考<Head First 设计模式>) 个人理解:装饰者就是一种类包类 就 ...

最新文章

  1. React和vue的差异和相似地方
  2. commit your changes or stash them before you can merge
  3. 180508 - 解决有关VIVO的2018-04-01安全补丁导致的APP闪退问题
  4. zookeeper - watcher(9)
  5. 修改mysql表的itemId字段为自增长SQL语句
  6. 使用MVC模式制作游戏-教程和简介
  7. 【算法实践】搜狗信息流推荐算法交流.pdf(附下载链接)
  8. 如何将cocos2d-x项目打包成一个.exe
  9. chinese-ocr自然场景下不定长文字识别(ctpn + densenet)
  10. Simulink模块之VCO(压控振荡器)
  11. ROC曲线及AUC值
  12. [Ubuntu] fg、bg让你的进程在前后台之间切换
  13. 激光雕刻机的位图-GCode转换方法实践
  14. 锐起无盘工作站网卡配置
  15. opencv 二值化处理
  16. python实现SG滤波
  17. steam linux不能运行,ubuntu 16.04下不能启动Steam的解决方法
  18. 教程:如何制作一个可控制的人体骨骼模型
  19. 大厂程序员都会的分布式RPC框架,直接无私打包分享,手慢无
  20. 数字IC设计的基本流程和主流EDA工具

热门文章

  1. win10更新双系统启动选项消失得解决方案
  2. java format用法_Java中String 的 format用法
  3. [139]python selenium之模拟键盘操作
  4. android主题商店,主题商店免费版
  5. win10英雄联盟登录服务器未响应,win10系统lol英雄联盟登录服务器未响应的恢复技巧...
  6. Excel如何按照指定顺序排列
  7. Python数据可视化 Pyecharts 制作 Boxplot 箱线图
  8. JAVA高考加油_高考祝福语给高三学生加油打气的话
  9. 斐波那契(黄金分割)查找
  10. wpf怎么让Textbox只能输入数字?