目录


  

  一、问题引入
  二、设计原则
  三、用装饰者模式解决问题
  四、装饰者模式的特点
  五、装饰者模式的定义
  六、装饰者模式的实现
  七、java.io包内的装饰者模式


一、问题引入

  咖啡店的类设计:

  一个饮料基类,各种饮料类继承这个基类,并且计算各自的价钱。

  饮料中需要加入各种调料,考虑在基类中加入一些布尔值变量代表是否加入各种调料,基类的cost()中的计算各种调料的价钱,子类覆盖cost(),并且在其中调用超类的cost(),加上特定饮料的价钱,计算出子类特定饮料的价钱。

  缺点:类数量爆炸、基类加入的新功能并不适用于所有的子类、调料价钱的改变、新调料的出现都会要求改变现有代码;有的子类并不适合某些调料等情况……

二、设计原则

  类应该对扩展开放,对修改关闭。

  我们的目标是允许类容易扩展,在不修改现有代码的情况下,就可搭配新的行为。

  如能实现这样的目标,有什么好处呢?这样的设计具有弹性可以应对改变,可以接受新的功能来应对改变的需求。

  要让OO设计同时具备开放性和关闭性,不是一件容易的事,通常来说,没有必要把设计的每个部分都这么设计。

  遵循开放-关闭原则,通常会引入新的抽象层次,增加代码的复杂度。

  我们需要把注意力集中在设计中最有可能改变的地方,然后应用开放-关闭原则。

三、用装饰者模式解决问题

  解决咖啡店饮料问题的方法:

  以饮料为主体,然后在运行时以调料来“装饰”饮料。

  比如,顾客想要摩卡(Mocha)和奶泡(Whip)深焙咖啡(DarkRoast):

  DarkRoast继承自Beverage,有一个cost()方法。

  第一步,以DarkRoast对象开始;

  第二步,顾客想要摩卡,所以建立一个Mocha装饰者对象,并用它将DarkRoast对象包装(wrap)起来;

  第三步,顾客想要奶泡,所以建立一个Whip装饰者对象,并用它将Mocha对象包起来;(Mocha和Whip也继承自Beverage,有一个cost()方法);

  最后,为顾客算钱,通过调用最外圈装饰者(Whip)的cost()就可以。Whip()的cost()会先委托它装饰的对象(Mocha)计算出价钱,然后在加上奶泡的价钱。Mocha的cost()也是类似。

四、装饰者模式的特点

  装饰者和被装饰对象有相同的超类型

  可以用一个或多个装饰者包装一个对象。

  因为装饰者和被装饰者具有相同的类型,所以任何需要原始对象的场合,可以用装饰过的对象代替。

  装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。

  对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰对象。

五、装饰者模式的定义

  装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

六、装饰者模式的实现

  实现类图如下:

装饰者和被装饰者具有共同的超类,利用继承达到“类型匹配”,而不是利用继承获得“行为”;将装饰者和被装饰者组合时,加入新的行为。

详细源码:

  1. package com.blankjor.decorator;
  2.  
  3. /**
  4. * @desc 抽象饮料类(抽象组件)
  5. * @author Blankjor
  6. * @date 2017年5月14日 上午11:14:06
  7. */
  8. public abstract class Beverage {
  9. String description = "Unkown Beverage";
  10.  
  11. public String getDescription() {
  12. return description;
  13. }
  14.  
  15. /**
  16. * 抽象价格计算方法
  17. *
  18. * @return
  19. */
  20. public abstract double cost();
  21. }
  22.  
  23. package com.blankjor.decorator;
  24.  
  25. /**
  26. * @desc 浓缩饮料 (具体组件)
  27. * @author Blankjor
  28. * @date 2017年5月14日 上午11:20:11
  29. */
  30. public class Espresso extends Beverage {
  31. public Espresso() {
  32. description = "Espresso";
  33. }
  34.  
  35. @Override
  36. public double cost() {
  37. return 1.99;
  38. }
  39.  
  40. }
  41.  
  42. package com.blankjor.decorator;
  43.  
  44. /**
  45. * @desc House Blend 饮料(具体组件)
  46. * @author Blankjor
  47. * @date 2017年5月14日 上午11:20:11
  48. */
  49. public class HouseBlend extends Beverage {
  50. public HouseBlend() {
  51. description = "House Blend";
  52. }
  53.  
  54. @Override
  55. public double cost() {
  56. return .20;
  57. }
  58.  
  59. }
  60.  
  61. package com.blankjor.decorator;
  62.  
  63. /**
  64. * @desc 抽象装饰者类
  65. * @author Blankjor
  66. * @date 2017年5月14日 上午11:17:12
  67. */
  68. public abstract class CondimentDecorator extends Beverage {
  69. /**
  70. * 为了后面的调料都能够获取到自己调料的描述
  71. */
  72. public abstract String getDescription();
  73.  
  74. }
  75.  
  76. package com.blankjor.decorator;
  77.  
  78. /**
  79. * @desc Mocha调料(具体装饰者)
  80. * @author Blankjor
  81. * @date 2017年5月14日 上午11:23:36
  82. */
  83. public class Mocha extends CondimentDecorator {
  84. Beverage beverage;
  85.  
  86. public Mocha(Beverage beverage) {
  87. this.beverage = beverage;
  88. }
  89.  
  90. @Override
  91. public String getDescription() {
  92. return beverage.getDescription() + ",Mocha";
  93. }
  94.  
  95. @Override
  96. public double cost() {
  97. return .20 + beverage.cost();
  98. }
  99. }
  100.  
  101. package com.blankjor.decorator;
  102.  
  103. /**
  104. * @desc Soy调料(具体装饰者)
  105. * @author Blankjor
  106. * @date 2017年5月14日 上午11:20:11
  107. */
  108. public class Soy extends CondimentDecorator {
  109. Beverage beverage;
  110.  
  111. public Soy(Beverage beverage) {
  112. this.beverage = beverage;
  113. }
  114.  
  115. @Override
  116. public String getDescription() {
  117. return beverage.getDescription() + ",Soy";
  118. }
  119.  
  120. @Override
  121. public double cost() {
  122. return .60 + beverage.cost();
  123. }
  124. }
  125.  
  126. package com.blankjor.decorator;
  127.  
  128. /**
  129. * @desc Whip调料(具体装饰者)
  130. * @author Blankjor
  131. * @date 2017年5月14日 上午11:20:11
  132. */
  133. public class Whip extends CondimentDecorator {
  134. Beverage beverage;
  135.  
  136. public Whip(Beverage beverage) {
  137. this.beverage = beverage;
  138. }
  139.  
  140. @Override
  141. public String getDescription() {
  142. return beverage.getDescription() + ",Whip";
  143. }
  144.  
  145. @Override
  146. public double cost() {
  147. return .40 + beverage.cost();
  148. }
  149. }
  150.  
  151. package com.blankjor.decorator;
  152.  
  153. /**
  154. * @desc 测试装饰者模式
  155. * @author Blankjor
  156. * @date 2017年5月14日 上午11:29:50
  157. */
  158. public class MainTest {
  159. public static void main(String[] args) {
  160. // 创建一种调料
  161. Beverage beverage = new Espresso();
  162. // 描述和价格
  163. System.out.println(beverage.getDescription() + " $" + beverage.cost());
  164. Beverage beverage1 = new HouseBlend();
  165.  
  166. beverage1 = new Mocha(beverage1);
  167. beverage1 = new Whip(beverage1);
  168. beverage1 = new Soy(beverage1);
  169. System.out.println(beverage1.getDescription() + " $" + beverage1.cost());
  170. Beverage beverage2 = new Espresso();
  171.  
  172. beverage2 = new Mocha(beverage2);
  173. beverage2 = new Whip(beverage2);
  174. beverage2 = new Soy(beverage2);
  175. beverage2 = new Mocha(beverage2);
  176. System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
  177. }
  178.  
  179. }

运行结果:

装饰者和被装饰者具有共同的超类,利用继承达到“类型匹配”,而不是利用继承获得“行为”;将装饰者和被装饰者组合时,加入新的行为。

  解决本文中饮料的具体问题时,图中Component即为Beverage(可以是抽象类或者接口),而ConcreteComponent为各种饮料,Decorator(抽象装饰者)为调料的抽象类或接口,ConcreteDecoratorX则为各种具体的调料。

  因为使用对象组合,可以把饮料和调料更有弹性地加以混合与匹配。

  代码外部细节:

  代码中实现的时候,通过构造函数将被装饰者传入装饰者中即可,如最后的调用形式如下:

    Beverage beverage = new DarkRoast();

    beverage = new Mocha(beverage);

    beverage = new Whip(beverage);

  即完成了两层包装,此时再调用beverage的cost()函数即可得到总价。

七、java.io包内的装饰者模式

装饰者模式的缺点:在设计中加入大量的小类,如果过度使用,会让程序变得复杂。

参考:http://www.cnblogs.com/mengdd/archive/2013/01/03/2843439.html

Java设计模式の装饰者模式的更多相关文章

  1. Java设计模式——装饰者模式

    JAVA 设计模式 装饰者模式 用途 装饰者模式 (Decorator) 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator 模式相比生成子类更为灵活. 装饰者模式是一种结构式模式 ...

  2. JAVA设计模式--装饰器模式

    装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰 ...

  3. 从源码角度理解Java设计模式——装饰者模式

    一.饰器者模式介绍 装饰者模式定义:在不改变原有对象的基础上附加功能,相比生成子类更灵活. 适用场景:动态的给一个对象添加或者撤销功能. 优点:可以不改变原有对象的情况下动态扩展功能,可以使扩展的多个 ...

  4. 【设计模式】Java设计模式 - 装饰者模式

    Java设计模式 - 装饰者模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 原创作品,更多关注我CSDN: 一个有梦有戏的人 准备将博客园.CSDN一起记录分享自 ...

  5. JAVA 设计模式 装饰者模式

    用途 装饰者模式 (Decorator) 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator 模式相比生成子类更为灵活. 装饰者模式是一种结构式模式. 结构

  6. Java 设计模式—装饰者模式

    在Java编程语言中,嵌套了非常多设计模式的思想,比如IO流中的缓冲流就使用到以下要介绍的装饰者设计模式. 演示样例代码: * 抽象构件角色:定义一个抽象接口,来规范准备附加功能的类 * @autho ...

  7. Java设计模式--装饰器模式到Java IO 流

    装饰器模式 抽象构件角色:给出一个抽象接口,以规范准备接受附加责任的对象. 具体构件角色:定义准备接受附加责任的对象. 抽象装饰角色:持有一个构件对象的实例,并对应一个与抽象构件接口一致的接口. 具体 ...

  8. JAVA设计模式---装饰者模式

    写在前面的话: 该模式动态的将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案.装饰者可以在被装饰者的行为前面与/或后面加上自己的行为,甚至将被装饰者的行为整个取代掉,而达到特定的 ...

  9. 设计模式-装饰者模式(Decorator Pattern)

    本文由@呆代待殆原创,转载请注明出处. 此设计模式遵循的设计原则之一:类应该支持扩展,而拒绝修改(Open-Closed Principle) 装饰者模式简述 装饰者模式通过组合的方式扩展对象的特性, ...

随机推荐

  1. tensorflow学习笔记(4)-学习率

    tensorflow学习笔记(4)-学习率 首先学习率如下图 所以在实际运用中我们会使用指数衰减的学习率 在tf中有这样一个函数 tf.train.exponential_decay(learning ...

  2. 【转载】Android 内存溢出如何发生的。

    [转载]Android 内存溢出如何发生的. 且谈Android内存溢出 前言 关于android的内存溢出在创新文档库中也有不少,网络上也有很多这方面的资料.所以这遍文章不算是正真意义上的创新,仅仅 ...

  3. Thunder团队第一次Scrum会议

    Scrum会议1 小组名称:Thunder 项目名称:待定 参会成员: 王航(Master):http://www.cnblogs.com/wangh013/ 李传康:http://www.cnblo ...

  4. angular4中使用jquer插件

    有以下办法 1 在html文档头部引入jquery插件依赖,但是文档一旦变动就麻烦了 2 使用指令:http://www.cnblogs.com/liuyt/p/5810100.html 指令是把利器 ...

  5. C# 如何在winform中嵌入Excel,内嵌Excel,word

    近使用.net做一个小软件遇到一个问题,就是想实现把excel表格在winform中打开,同时可以操作,不单单是打开.或者就提取数据.在网上找了好多资料,发现这方面的资料比较少,即使有,都是旧版本的使 ...

  6. 在Centos中,大容量,且读写频繁的目录

    1./根目录 2./usr目录 3./home目录 4./var目录 5./Swap目录     比较特殊,只要物理内存没使用完,就不会被启用 以上为鸟哥的linuxPDF中的学习心得

  7. (转)NEST.net Client For Elasticsearch简单应用

    由于最近的一个项目中的搜索部分要用到 Elasticsearch 来实现搜索功能,苦于英文差及该方面的系统性资料不好找,在实现时碰到了不少问题,现把整个处理过程的代码分享下,给同样摸索的人一些借鉴,同 ...

  8. set类型没有单独取值功能 通过循环取值

    set类型没有单独取值功能 通过循环取值

  9. Codeforces Round#516 Div.1 翻车记

    A:开场懵逼.然后发现有人1min过,于是就sort了一下,于是就过了.正经证明的话,考虑回文串两端点一定是相同的,所以最多有Σcnti*(cnti+1)/2个,cnti为第i种字母出现次数.而sor ...

  10. ZOJ1081:Points Within——题解

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1081 题目大意:给定一个点数为 n 的多边形,点按照顺序给出,再给出 m ...