装饰者模式

打印 上一主题 下一主题

主题 884|帖子 884|积分 2652

装饰者模式

咖啡案例引入


  • 1.咖啡种类,有意大利咖啡(Espresso),ShortBlack,美式咖啡(LongBlack),无因咖啡(Decaf)。
  • 2.调料,Milk,Soy(豆浆),Chocolate(巧克力)。
  • 3.要求再扩展新的咖啡种类时,具有良好的扩展性,改动方便,维护方便。
  • 4.客户可以点单品咖啡,也可以点单品 + 调料组合。
方案1类图


方案1类图分析


  • 1.Drink是抽象类,表示饮料。
  • 2.description是对咖啡的描述,如咖啡的名字。
  • 3.cost()是计算费用,Drink类中定义为抽象的。
  • 4.Decaf等就是单品咖啡,继承Drink,重写cost()。
  • 5.Espresso && Milk就是单品咖啡 + 调料,这个组合很多。
  • 6.这样设计,会有很多类,当我们增加一个单品咖啡,或者一个新的调料,类的数量就会暴增,会出现类爆炸。
方案2类图


类图分析

方案1会出现,咖啡单品 + 调料组合会造成类的倍增,因此可以做改进,将调料内置在Drink中,这样就不会出现类爆炸,提高项目的可维护性。说明milk,soy,chocolate可以设计为Boolean,表示是否要添加相应的调料。

  • 1.方案2可以控制类数量,避免类爆炸情况。
  • 2.但在增加和删除调料时,代码的维护量还是很大。
  • 3.用户点多份调料的情况,可以返回一个int值,代表份数。
  • 4.可以考虑使用装饰者模式。
基本介绍


  • 1.装饰者模式(Decorator Pattern),动态的将新功能附加到对象上。在对象扩展方面,比继承更有弹性,装饰者模式也提醒了开闭原则(ocp)。
  • 2.这里提到的动态附加新功能到对象上,和ocp,在案例中有体现。
装饰者原理举例


  • 1.装饰者模式就像打包一个快递。主体是衣服,陶瓷等,包装,比如塑料,泡沫,木板等。这样构成一个完整的快递。
  • 2.主体,就是Drink(被装饰者),包装就是Decorator(装饰者)。
装饰者模式实现案例类图


说明,类图中的Decorator应该是继承Drink,然后在Decorator中组合一个 Drink drink属性;
  1. //饮品
  2. public abstract class Drink {
  3.     private String des;
  4.     private float price;
  5.     public String getDes() {
  6.         return des;
  7.     }
  8.     public void setDes(String des) {
  9.         this.des = des;
  10.     }
  11.     public float getPrice() {
  12.         return price;
  13.     }
  14.     public void setPrice(float price) {
  15.         this.price = price;
  16.     }
  17.     public abstract float cost();
  18. }
  19. //咖啡父类
  20. public class Coffee extends Drink {
  21.     @Override
  22.     public float cost() {
  23.         return super.getPrice();
  24.     }
  25. }
  26. public class Decaf extends Coffee{
  27.     public Decaf(){
  28.         setDes(" 无因咖啡 ");
  29.         setPrice(3.0f);
  30.     }
  31. }
  32. public class Espresso extends Coffee{
  33.     public Espresso(){
  34.         setDes(" 意大利咖啡 ");
  35.         setPrice(6.0f);
  36.     }
  37. }
  38. public class LongBlack extends Coffee{
  39.     public LongBlack(){
  40.         setDes(" 美式咖啡 ");
  41.         setPrice(5.0f);
  42.     }
  43. }
  44. public class ShortBlack extends Coffee{
  45.     public ShortBlack(){
  46.         setDes(" 黑咖啡 ");
  47.         setPrice(5.0f);
  48.     }
  49. }
  50. /**
  51. * @author 长名06
  52. * @version 1.0
  53. * 修饰者 是调料的父类
  54. */
  55. public class Decorator extends Drink{
  56.     private Drink drink;//组合一个drink
  57.     public Decorator(Drink drink){
  58.         this.drink = drink;
  59.     }
  60.     @Override
  61.     public float cost() {
  62.         //super.getPrice()代表小料的价格 drink.cost()代表饮料的价格
  63.         return super.getPrice() + drink.cost();
  64.     }
  65.     @Override
  66.     public String getDes() {
  67.         //重写描述方法
  68.         return super.getDes() + getPrice() + " && " + drink.getDes();
  69.     }
  70. }
  71. public class Milk extends Decorator{
  72.     public Milk(Drink drink){
  73.         super(drink);
  74.         setDes(" 牛奶 ");
  75.         setPrice(2.0f);
  76.     }
  77. }
  78. public class Soy extends Decorator{
  79.     public Soy(Drink drink){
  80.         super(drink);
  81.         setDes(" 豆浆 ");
  82.         setPrice(3.0f);
  83.     }
  84. }
  85. public class Chocolate extends Decorator{
  86.     public Chocolate(Drink drink){
  87.         super(drink);
  88.         setDes(" 巧克力 ");
  89.         setPrice(3.0f);
  90.     }
  91. }
  92. //测试
  93. public class Client {
  94.     public static void main(String[] args) {
  95.         //下订单,买2份巧克力 + 1份牛奶的LongBlack咖啡
  96.         //1.买一份LongBlack咖啡
  97.         //咖啡要用Drink接收,不能使用自己的咖啡类型
  98.         //因为被小料修饰过的咖啡的类型是对应的小料类型
  99.         //如果用自己的咖啡类型,就不能完成 修饰过的咖啡 赋给原有的咖啡了
  100.         Drink longBlack = new LongBlack();
  101.         System.out.println("LongBlack咖啡价格 " + longBlack.cost());
  102.         System.out.println("LongBlack咖啡描述 " + longBlack.getDes());
  103.         //2.给LongBlack咖啡,加一个牛奶小料
  104.         longBlack = new Milk(longBlack);
  105.         System.out.println("加一个牛奶小料的LongBlack咖啡价格 " + longBlack.cost());
  106.         System.out.println("加一个牛奶小料的LongBlack咖啡描述 " + longBlack.getDes());
  107.         //3.给LongBlack咖啡,加一个巧克力小料
  108.         longBlack = new Chocolate(longBlack);
  109.         System.out.println("加一个牛奶小料 加一个巧克力小料的LongBlack咖啡价格 " + longBlack.cost());
  110.         System.out.println("加一个牛奶小料 加一个巧克力小料的LongBlack咖啡描述 " + longBlack.getDes());
  111.         //4.给LongBlack咖啡,加两个巧克力小料
  112.         longBlack = new Chocolate(longBlack);
  113.         System.out.println("加一个牛奶小料 加两个巧克力小料的LongBlack咖啡价格 " + longBlack.cost());
  114.         System.out.println("加一个牛奶小料 加两个巧克力小料的LongBlack咖啡描述 " + longBlack.getDes());
  115.         System.out.println("==============");
  116.         Drink decaf = new Decaf();
  117.         System.out.println(decaf.cost());
  118.         System.out.println(decaf.getDes());
  119.         decaf = new Soy(decaf);
  120.         System.out.println("加一个豆浆小料的LongBlack咖啡价格 " + decaf.cost());
  121.         System.out.println("加一个豆浆小料的LongBlack咖啡描述 " + decaf.getDes());
  122.     }
  123. }
复制代码
装饰者模式在JDK应用分析

  1. import java.io.DataInputStream;
  2. import java.io.FileInputStream;
  3. /**
  4. * @author 长名06
  5. * @version 1.0
  6. */
  7. public class AnalysisDecoratorIO {
  8.     public static void main(String[] args) throws Exception{
  9.         //JDK源码中就使用到了装饰者模式
  10.         //1.InputStream是抽象类,类似我们前面讲的Drink
  11.         //2.FileInputStream是InputStream子类,类似我们前面的 DeCaf, LongBlack
  12.         //3. FilterInputStream是InputStream子类:类似我们前面的Decorator修饰者
  13.         //4. DataInputStream是 FilterInputStream子类,具体的修饰者,类似前面的Milk, Soy 等
  14.         // 5.FilterInputStream类有 protected volatile InputStream in属性 ;即含被装饰者
  15.         //6.分析得出在jdk 的io体系中,就是使用的装饰者模式
  16.         DataInputStream dis = new DataInputStream(new FileInputStream("d:\\abc.txt"));
  17.     }
  18. }
复制代码
只是为了记录自己的学习历程,且本人水平有限,不对之处,请指正。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

千千梦丶琪

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表