设计模式之装饰者模式

装饰者模式

 引入一个例子,比如去咖啡店喝咖啡,有些人喜欢不加糖不加牛奶的咖啡,有些人喜欢和加糖但是不加牛奶,还有些人喜欢和加牛奶但不加糖,亦有人喜欢两者都加。

 先用 Java 的继承方式看一看能不能很好的解决这个问题,首先定义一个咖啡类

public class Coffe {

    // 咖啡是否加配料描述
    protected String description;

    // 咖啡的价钱
    protected Double cost;

    // 默认咖啡什么都不加
    // 价格 10 块
    public Coffe(){
        this.description = "咖啡";
        this.cost = 10.0;
    }

    // 返回咖啡加配料的描述
    public String getDescription(){
        return description;
    }

    // 返回价格
    public double getCost(){
        return cost;
    }

}

然后定义加糖、加牛奶、加牛奶和糖的子类

加糖的子类:

public class CoffeWithSugar extends Coffe {


    public CoffeWithSugar(){
        super.description = "加糖的咖啡";
    }

    @Override
    public double getCost() {
        return super.getCost() + 2;
    }
}

加牛奶的子类:

    public CoffeWithMilk(){
        super.description = "加牛奶的咖啡";
    }

    @Override
    public double getCost() {
        return super.getCost() + 2;
    }
}

既加糖又加牛奶的子类

public class CoffeWithSugarMilk extends Coffe{
    public CoffeWithSugarMilk(){
        super.description = "加糖加牛奶的咖啡";
    }

    @Override
    public double getCost() {
        return super.getCost() + 6;
    }
}

 现在需要加什么的咖啡就只需要直接 new 相关的对象就可以了。感觉好像 Java 的继承也可以很好的解决这个问题,那要什么设计模式,好好写代码不香吗?非要整这么多花里胡哨的设计模式?难道设计模式是用来装X的?
 非也非也,如果牛奶涨价了,是不是需要重新修改 CoffeWithMilk 和 CoffeWithSugarMilk 这两个类,违反了开闭原则(开闭原则:软件实体(类、模块、方法)应该对扩展开发,对修改关闭),每次一有价格的波动就需要两个及以上的类。如果以后添加其他配料的话还要添加更多的子类,如果有变动那么就要修改更多的类,这对后期维护造成很大的麻烦。

 下面主角登场——装饰者模式,首先,装饰者模式有一些关键点,根据《Head First Design Pattern》中的描述:

  1. 装饰者和被装饰者必须有相同的父类。
  2. 可以用一个或多个装饰者装饰一个对象。
  3. 既然装饰者和被装饰者有相同的父类,那么任何出现原始对象(被装饰者)的地方,都可以使用装饰过得对象代替。
  4. 装饰者可以在所委托被装饰者的行为之前或之后,加上自己的行为,以达到特定的目的。
  5. 对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来修饰对象。

 以上就是使用装饰者模式需要注意的点,但这么看有点抽象,不太好理解。先上例子:

首先定义一个咖啡的抽象类,因为第一点:装饰者和被装饰者必须有相同的父类

public abstract class ACoffe {

    private String description;

    private Double cost;

    protected abstract String getDescription();

    protected abstract double getCost();

}

咖啡的实现类

public class Coffe extends ACoffe{
    @Override
    protected String getDescription() {
        return "咖啡";
    }

    @Override
    protected double getCost() {
        return 10;
    }
}

装饰父类,这个装饰父类也可以定义为实现类,但是为了更好(好像并没有)的演示装饰者模式,在这里就定义为抽象类了。

public abstract class AbstractDecorator extends ACoffe{
    protected ACoffe aCoffe;

    public AbstractDecorator(ACoffe aCoffe){
        this.aCoffe = aCoffe;
    }

    @Override
    protected abstract String getDescription();

    @Override
    protected abstract double getCost();
}

糖的装饰类

public class SugarDecorator extends AbstractDecorator {

    public SugarDecorator(ACoffe aCoffe) {
        super(aCoffe);
    }

    @Override
    protected String getDescription() {
        return super.aCoffe.getDescription() + " 加糖";
    }

    @Override
    protected double getCost() {
        return super.aCoffe.getCost() + 2;
    }
}

牛奶的装饰类

public class MilkDecorator extends AbstractDecorator {
    public MilkDecorator(ACoffe aCoffe) {
        super(aCoffe);
    }

    @Override
    protected String getDescription() {
        return super.aCoffe.getDescription() + " 加牛奶";
    }

    @Override
    protected double getCost() {
        return super.aCoffe.getCost() + 4;
    }
}

测试,这里可以加任意多次糖和牛奶,也可以什么都不加

public static void main(String[] args) {

        ACoffe coffe = new Coffe();
        coffe = new SugarDecorator(coffe);
        coffe = new MilkDecorator(coffe);
        System.out.println(coffe.getDescription() + "   " + coffe.getCost());
    }

运行结果

咖啡 加糖 加牛奶   16.0

还有一种非常熟悉的写法

public static void main(String[] args) {
        ACoffe coffe = new SugarDecorator(new MilkDecorator(new Coffe()));
        System.out.println(coffe.getDescription() + "   " + coffe.getCost());
    }

是不是有一种似曾相识的感觉,想一想,好好想一想在哪里见过。






















BufferedInputStream bis = new BufferedInputStream(new FileInputStream("test.txt"));

是不是这个,其实 Java I/O 流中的包装流就是用的装饰者模式。

总结:
装饰者模式与类继承的比较
装饰者模式:

  1. 用于扩展 对象 的功能
  2. 不需要子类
  3. 可以动态扩展
  4. 每个装饰类有特定的职责
  5. 有效防止子类过多而导致混乱
  6. 灵活

类继承

  1. 用于扩展 的功能
  2. 需要子类
  3. 编译时分派职责
  4. 会有很多子类产生
  5. 不灵活

装饰者模式的定义与优缺点
装饰者模式在不改变原有类的基础上动态地将责任附加到对象上。提供了比继承更有弹性的替代方案。
优点:
灵活,不用修改原有类,可以选择不同的装饰类实现不同的效果,符合开闭原则
缺点
比继承复杂

这是第一次写博客,如果有写的不好的或者错误的地方,请各位大佬批评指正。
over! 睡觉

全部评论

相关推荐

1 收藏 评论
分享
牛客网
牛客企业服务