zoukankan      html  css  js  c++  java
  • 10分钟一个设计模式系列-The Decorator Pattern

    10分钟一个设计模式系列

    The Decorator Pattern

    1.Basic 基础

    为何称这个模式为Decorator模式呢。我们先来看一个例子,一家咖啡店,有很多种类型的饮品,如DarkRoast, HouseBlend, Espresso等等。不同类型的饮品,还能加入不同的调料,例如牛奶,Mocha, 大豆等等。那么这样这些饮品将会有多种各式各样的组合类型。

    那么在设计的时候,不容置疑需要一个类作为各种饮品的基类,这个类我们可以命名为Beverage,Beverage类有cost()方法以及getDescription()方法,分别获得价格以及饮品描述,但如何实现各个子类呢?难道每个特定种类的饮料都要涉及一个子类么?这会引发“类爆炸”(class explosion),可以参加《Head First Design Patterns》英文版P81,抱歉本人并不知道是否有中文版以及中文版具体页数。

    结合现实例子,我们可以这样考虑,像DarkRoast, HouseBlend, Espresso这些,都是特定咖啡种类,而制成一杯饮品,无非是在这些饮品里面添加调味料(Condiments)。那如果我们可以用两个子类来继承Beverage,一个代表饮品“类型”,一个代表“调味料”的基类。当你需要在饮品“添加”调味料时,再不断地添加调味料,价格再去累加,这样的设计更加合理,在这里,调味料就是Decorator,而饮品种类就是Component。这就是Decorator模式。

    2. Implementation 实现

    那我们来看看具体如何实现这个例子。

    首先是基类Beverage:

    1 public abstract class Beverage {
    2  String description = "Unknown Beverage";
    3  
    4  public String getDescription() {
    5      return description;
    6  }
    7  
    8  public abstract double cost();
    9 }

    而Component和Decorator都需要继承这个基类,因为他们都具有Description以及Cost。

    接下来是各种Component:

    例如Espresso以及House Blend:

    1 public class Espresso extends Beverage{
    2  public Espresso() {
    3     description = "Espresso"; 
    4  }
    5  public double cost() {
    6      return 1.99;
    7  }
    8 }
    public class HouseBlend extends Beverage{
        public HouseBlend() {
            description = "House Blend Coffee";
        }
        
        public double cost() {
            return .89;
        }
    
    }

    CondimentDecorator,负责condiment的抽象类:

    1 public abstract class CondimentDecorator extends Beverage{
    2   public abstract String getDescription();
    3 }

    接下来继承CondimentDecorator的子类很重要,例如Mocha类,注意里面有一个Beverage的的子类实例去作为代理去delegate,来实现给这个实例添加“调味料”。

     1 public class Mocha extends CondimentDecorator{
     2  Beverage beverage;
     3  public Mocha(Beverage beverage) {
     4      this.beverage = beverage;
     5  }
     6  
     7  public String getDescription() {
     8      return beverage.getDescription() + ", Mocha";
     9  }
    10  
    11  public double cost() {
    12      return beverage.cost()+.20;
    13  }
    14 }

    最后是测试代码:

     1 public class test {
     2  public static void main(String[] args) {
     3      Beverage beverage = new Espresso();
     4      System.out.println(beverage.getDescription()+" $"+beverage.cost());
     5      Beverage beverage2 = new HouseBlend();
     6      System.out.println(beverage2.getDescription()+ " $"+beverage2.cost());
     7      
     8      //add some condiment
     9      beverage2 = new Mocha(beverage2);
    10      beverage2 = new Mocha(beverage2);
    11      System.out.println(beverage2.getDescription()+" $"+beverage2.cost());
    12  }
    13 }

    3. Java I/O 

    其实在Java里,I/O类其实就用了Decorator模式,我们来看看java.io.*的继承关系。

     

     可以看到,FilterInputStream是一个抽象的Decorator类,而FileInputStream, StringBufferInputStream, ByteArrayInputStream则为Component类。

    4.Decorator Pattern的“黑暗面”  Dark Side

    首先,Decorator模式比较难读懂,不够直观。另外,当你创建一个Component实例时,你不单仅仅创建Component实例,你同时需要创建Decorator去修饰(wrap)它。这就造成了编写代码过程的复杂化。但这些问题并不代表Decorator不是一个好的设计模式,设计模式本质上说并无好坏之分,就像根本不存在完美的高内聚低耦合代码,只有不断地尝试去"折中"它。

  • 相关阅读:
    (转)WinForm中的各种表格控件
    sql2005 单用户改为多用户sql语句
    使用sp_executesql执行动态SQL语句,同时向里面传入参数。
    visual studio 不能创建biztalk 项目
    sql2005 无法连接服务器 1433端口没有监听,但是本地帐户可以登陆
    visual studio运行时提示无法启动应用程序
    将表中的数据生成插入语句
    sql 补零方法
    正则表达式,动态生成小数点位数的验证
    “本地计算机上的SQL SERVER服务启动后又停止了”解决方法
  • 原文地址:https://www.cnblogs.com/Jam01/p/3641893.html
Copyright © 2011-2022 走看看