设计模式之装饰者模式

一:装饰者模式

将最初的对象用一层一层外衣(修饰者)包装起来,实现自由组合。

举个栗子:
最初的对象:咖啡
外衣:糖,牛奶,豆浆…

我可以将上面的类型自由组合,比如
咖啡加糖和牛奶 或者 咖啡加豆浆 或者 咖啡加糖和豆浆 或者 ...

二:不使用装饰者模式

实现上面的栗子,如果没有使用装饰者模式,类图可能是这样:

这里写图片描述

缺点非常明显:

  • 有多少种组合就必须自己实现多少个子类
  • 设计子类时必须严格考虑,比如没有人在咖啡中加牛奶又加豆浆
  • 子类的cost()方法实现具体价格的计算,那要是牛奶价格上升,调整与牛奶相关的每一个子类中的cost()方法将会使你奔溃。

三:使用装饰者模式

基本原则是我们定义一种公共类型A,每个A中有相同的方法,参数都是同一种类型A,这样我们可以一层一层在原始咖啡上加东西。假设像下面这样调用我就能返回相应的价格。

 CoffeeWithMilk = new Milk(new Coffee());     //CoffeeWithMilk.cost()  就能返回`咖啡加牛奶`价格

再来个稍微复杂的

CoffeeWithMilkAndSugar = new Milk(new Sugar(new Coffee())); 
// 同理 CoffeeWithMilkAndSugar.cost()就能返回`咖啡加牛奶加糖`的价格。

那要怎么实现呢:

这里写图片描述

Beverage 是饮料类,也是基类。派生出了两种咖啡类EspressoDecaf,当然它也可以派生别的饮料,比如等等。CondimentDecorator叫调料装饰类,之所以要定义它,表明它的子类都是用来修饰饮料的,我们也可以让MochaMilk直接继承自Beverage,但是这样以后可能不太方便。

现在我的系统变的可以自由组合了。

四:代码如下

Beverage.java

public abstract class Beverage {

    String Description = "";

    public String getDescription() {
        return Description;
    }

    public abstract double cost();

}

Espresso.java

public class Espresso extends Beverage {

    private static final double CostOfEspresso = 1.22;

    public Espresso() {
        Description  = "Espresson";
    }

    public double cost() {
        return CostOfEspresso;
    }
}

Decaf.java

public class Decaf extends Beverage {

    private static final double CostOfDecaf = 1.55;

    public Decaf() {
        Description = "Decaf";
    }

    public double cost() {
        return CostOfDecaf;
    }
}

CondimentDecorator.java

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

Mocha.java

public class Mocha extends Beverage {

    private static final double CostOfMocha = 0.22;
    Beverage beverage;

    public Mocha(Beverage be) {
        this.beverage = be;

    }

    public String getDescription() {
        return beverage.getDescription() + "";
    }

    public double cost() {
        return beverage.cost()+ CostOfMocha;
    }
}

Milk.java

public class Milk extends CondimentDecorator {

    private static final double CostOfMilk = 0.33;
    Beverage beverage;

    public Milk(Beverage be) {
        this.beverage = be;
    }

    public String getDescription() {
        return beverage.getDescription() + "Milk,";
    }

    public double cost() {
        return beverage.cost()+CostOfMilk;
    }
}

mian.java

public class main {
    public static void main(String[] args) {
        Beverage cof = new Espresso();
        System.out.println(cof.getDescription()+ "  $: "+ cof.cost());

        Beverage cof1 = new Milk(new Decaf());
        System.out.println(cof1.getDescription()+ "  $: "+ cof1.cost());

        Beverage cof2 = new Milk(new Mocha(new Espresso()));
        System.out.println(cof2.getDescription()+ "  $: "+ cof2.cost());

    }
}

这里写图片描述

五 :优点

优点(针对上面的缺点):

  • 不用再设计那么多子类了,只需要有最基础的每个子类就好,少了组合的数量。
  • 可以自由组合,我们大不了不会喝牛奶加豆浆罢了,如果真有人喝,那我们也可以组合出来。
  • 现在如果牛奶涨价,只用在Milk.java中将它的价格CostOfMilk更新即可,别的都不用动,是不是非常方便。

六:后续工作

  • JDK中的I/O类大量使用了装饰者模式,后续看看。

posted on 2016-12-01 11:33  杨博东的博客  阅读(26)  评论(0编辑  收藏  举报

导航