设计模式系列之二:装饰者模式(Decorator Pattern)

来源:互联网 发布:deepin 添加ubuntu 源 编辑:程序博客网 时间:2024/06/15 15:03

这一阵还是比较忙,说好的两天一更都达不到,看来自己还是得努力。

装饰者模式其实普遍存在于我们的生活抽象中。现存的一些资料是以一个星巴克咖啡店来举例说明的,这里我们就用煎饼果子来举例吧,生动形象。

一个煎饼果子(Pancake rolled with crisp fritter 百度翻译。。不妨称之为Pancake)值5元,那么此时我加一个蛋(1元吧,虽然不切实际),总价为6元。我加一个肠(姑且2元)呢?那就是5+2=7元一个肠和一个蛋呢?5+1+2=8元两个肠和一个蛋呢?5+4+1=10元土豪级套餐n个肠n个蛋呢。。

看完这个,相信你大概马上想到了如下结构:

/** * Created by youweixi on 15/11/22. * 煎饼果子 */public class Pancake {    /**     * 煎饼价格     * */    private static int price = 5;    /**     * 加蛋数量     * */    private int eggNum = 0;    /**     * 加肠数量     * */    private int hotdogNum = 0;    /**     * 价格     * */    private int getCost(){        return price + eggNum * 1 + hotdogNum * 2;    }}

这样写很完美,对于这个问题这个类很适合。

现在煎饼果子要拓展业务,要做出如下价格改变。1. 新增可以加培根2. 蛋的价格调成3元一个3. 一种新的煎饼不能加蛋和培根

代码随需求而变。
1. 为了加上培根,我们不得不在主类上面添加Bacon的成员和修改方法,还要修改getCost方法。
2. 为了更改蛋的价格需要更改getCost方法。
3. 第三个问题虽然只是一个约束,但是此时eggNum和baconNum在这个类中就不会用到。

再比如说电商搞活动,打折券有不同的种类,可以叠加用,有的打折券是针对某一类商品,有些打折券是针对所有商品,在这个问题中,恐怕就不能为每一个商品都加上是否应用了打折券的成员变量(也许某一个打折券只有一天有效呢,我们却为他修改了所有的商品)。

基于这种问题,我们逐渐总结出了装饰者模式

其实这个模式相对固定,即对一个类可以重复的用不同的装饰类来装饰,最终通过函数嵌套回调来实现逐层解包的效果。

记住三点即可:
1. 基类和装饰类的基类是相同的->所以可以多次重复打包,装饰类中有超类成员变量
2. 虚方法在基类中已经定义但未实现->所以可以函数回源逐层解包
3. 装饰类和基类的继承类分开但同源->进行扩展时源代码不变,修改时对症下药

基本装饰类图

有了这个模式,我们就可以重新设计我们的代码来实现我们的煎饼果子铺:
我们的类图

/** * Created by youweixi on 15/11/22. * 煎饼果子铺的超类 */public abstract class Component {    protected String description = "Do You Know Who I Am ?";    protected abstract int getCost();    protected abstract String getDescription();}
/** * Created by youweixi on 15/11/22. * 煎饼果子类(继承了Component超类,由于我们之后有具体实现类,所以这里定义为抽象类) */public abstract class Pancake extends Component{    /**     * 描述     * */    private String description = "煎饼果子";    /**     * 价格     * */    @Override    public int getCost(){        return 5;    }    @Override    protected String getDescription() {        return this.description;    }}
/** * Created by youweixi on 15/11/22. * 高级版 */public class PancakeAverage extends Pancake {    /**     * 价格,高级版要加2元     * */    @Override    public int getCost(){        return super.getCost() + 2;    }    @Override    protected String getDescription() {        return super.getDescription() + ":高级版";    }}
/** * Created by youweixi on 15/11/22. * 普通版 */public class PancakeNormal extends Pancake {    @Override    protected String getDescription() {        return super.getDescription() + ":普通版";    }}

装饰类中间层

/** * Created by youweixi on 15/11/22. * 装饰者中间层 */public abstract class Decorator extends Component {}
/** * Created by youweixi on 15/11/22. * 培根装饰类 */public class DecoratorBacon extends Decorator{    /**     * 超类成员     * */    protected Component component;    /**     * 构造方法     * */    public DecoratorBacon (Component component){        this.component = component;    }    /**     * 培根3元一份     * */    @Override    protected int getCost() {        return component.getCost() + 3;    }    @Override    protected String getDescription() {        return component.getDescription() + " 培根*1";    }}
/** * Created by youweixi on 15/11/22. * 加蛋装饰类 */public class DecoratorEgg extends Decorator{    /**     * 超类成员     * */    protected Component component;    /**     * 构造方法     * */    public DecoratorEgg (Component component){        this.component = component;    }    @Override    protected int getCost() {        return component.getCost() + 1;    }    @Override    protected String getDescription() {        return component.getDescription() + " 蛋*1";    }}
/** * Created by youweixi on 15/11/22. * 加肠装饰类 */public class DecoratorHotdog extends Decorator{    /**     * 超类成员     * */    protected Component component;    /**     * 构造方法     * */    public DecoratorHotdog (Component component){        this.component = component;    }    @Override    protected int getCost() {        return 0;    }    @Override    protected String getDescription() {        return null;    }}

至此,整个程序体系就写好了。

调用看一下效果:

public static void main(String[] args){        //购买一个普通版        Component p1 = new PancakeNormal();        //加一个培根        p1 = new DecoratorBacon(p1);        //加一个蛋        p1 = new DecoratorEgg(p1);        System.out.println("Description:" + p1.getDescription() + " Price:" + p1.getCost() + "\n\n");        //购买一个高级版        Component p2 = new PancakeAverage();        //加一个培根        p2 = new DecoratorBacon(p2);        //再加一个培根        p2 = new DecoratorBacon(p2);        //加一个蛋        p2 = new DecoratorEgg(p2);        //加一个肠        p2 = new DecoratorHotdog(p2);        System.out.println("Description:" + p2.getDescription() + " Price:" + p2.getCost());    }

结果正确

Description:煎饼果子:普通版 培根*1*1 Price:9Description:煎饼果子:高级版 培根*1 培根*1*1 热狗*1 Price:16

可以看出这种模式适合抽象为包装类应用,在应用这种设计模式的时候务必理清楚业务逻辑,分清装饰类和主类,具体层次就会清晰很多了。

有兴趣的同学可以具体查一下JAVA IO体系的输入输出流,同样也是这样的设计模式,在此不作赘述了。

1 0