27
2017
09

设计模式(3)---装饰者模式

定义

动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

理解

就拿奶茶来说,各种xx奶茶,其实从结构来看,成分有两种:

  • 被装饰者:原味奶茶
  • 各种装饰者:椰果、珍珠、红豆 等等。

在装饰者模式中,一共有四个角色:共有超类(接口)、被装饰者、装饰者的抽象类(接口)、装饰者:

  • 共同的基类(接口) — “奶茶”:是被装饰者和装饰者共有的超类(接口)。
  • 被装饰者 — 原味奶茶:和常规的相同,extends(implements)”奶茶”就行。
  • 装饰者的抽象类(接口) — “装饰”:“是所有装饰者的超类(接口),和常规的相同,直接extends(implements)”奶茶”。
  • 装饰者 — 椰果、珍珠、红豆 等等:extends(implements)“装饰”,然后在构造函数中传入”奶茶”,这样装饰者不光从类型上能完全取代被装饰者,还能新增自己特有的功能。

“装饰”二字是重点,让我想到了《Android开发艺术探索》里关于属性动画的一个小demo

    private void performAnimate() {
        ButtonWrapper buttonWrapper = new ButtonWrapper(button);
        ObjectAnimator.ofInt(buttonWrapper,"width",200,400)
                .setDuration(1000)
                .start();
    }

    public void onClick(View view) {
        performAnimate();
    }

public class ButtonWrapper {
    private View mTarget;

    public ButtonWrapper(View mTarget) {
        this.mTarget = mTarget;
    }

    public int getWidth(){
        return mTarget.getLayoutParams().width;
    }

    public void setWidth(int width){
        mTarget.getLayoutParams().width = width;
        mTarget.requestLayout();
    }
}

在这个例子中,Button类本身没有getWidth()和setWidth(),但是可以通过一个Wrapper类将Button包装起来,增加这两个方法,然后去属性动画。
只不过装饰者模式情况更特殊,包装类和被包装类有共同的超类,这种特殊的方式能让装饰后的类完全替代被装饰类,也就意味着装饰后还可以继续装饰。是不是让你想到了java.io中的 FileInputStream、BufferedInputStream,其实他们本身用的就是装饰者模式。


有人就会产生疑问:从继承上来看,难道”椰果 is a 奶茶”?,实际上装饰者模式中的继承(实现),并不是为了获取行为,而是“类型匹配”。利用多态的特性,保证了装饰后的类还能继续被装饰。

UML图

这里写图片描述

代码

基类MilkTea 及其实现类OriginalMilkTea

public abstract class MilkTea {

    String description = "奶茶";

    public String getDescription(){
        return description;
    }

    public abstract double cost();
}

public class OriginalMilkTea extends MilkTea {

    public OriginalMilkTea() {
        description = "OriginalMilkTea";
    }

    @Override
    public double cost() {
        return 10.0;
    }
}

装饰者抽象类及其实现

public abstract class Decorator extends MilkTea{

    public abstract double cost();
    public abstract String getDescription();
}

public class YeGuo extends Decorator {

    MilkTea milkTea;

    public YeGuo(MilkTea milkTea) {
        this.milkTea = milkTea;
    }

    @Override
    public String getDescription() {
        return milkTea.getDescription() + ",YeGuo";
    }

    @Override
    public double cost() {
        return milkTea.cost() + 2.0;
    }
}

public class ZhenZhu extends Decorator {

    MilkTea milkTea;

    public ZhenZhu(MilkTea milkTea) {
        this.milkTea = milkTea;
    }

    @Override
    public String getDescription() {
        return milkTea.getDescription() + ",ZhenZhu";
    }

    @Override
    public double cost() {
        return milkTea.cost() + 1.0;
    }
}

public class HongDou extends Decorator {

    MilkTea milkTea;

    public HongDou(MilkTea milkTea) {
        this.milkTea = milkTea;
    }

    @Override
    public String getDescription() {
        return milkTea.getDescription() + ",HongDou";
    }

    @Override
    public double cost() {
        return milkTea.cost() + 3.0;
    }
}

测试:

MilkTea milkTea = new OriginalMilkTea();
YeGuo yeGuo = new YeGuo(milkTea);
ZhenZhu zhenZhu = new ZhenZhu(yeGuo);
HongDou hongDou = new HongDou(zhenZhu);
Log.e("ZXK","hongDou---cost:"+hongDou.cost()+"---description:"+hongDou.getDescription());

结果:

hongDou---cost:16.0---description:OriginalMilkTea,YeGuo,ZhenZhu,HongDou
上一篇:Swift Label计算高度 下一篇:MediaStore.Images.Media.insertImage