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不是一个好的设计模式,设计模式本质上说并无好坏之分,就像根本不存在完美的高内聚低耦合代码,只有不断地尝试去"折中"它。

原文地址:https://www.cnblogs.com/Jam01/p/3641893.html