设计模式3——装饰者模式

左心房为你撑大大i 提交于 2020-02-03 08:59:34

定义:动态的将责任附加到对象上。若要扩展功能,装饰者提供了比继承更加弹性的解决方案。


1 引例_咖啡订单系统

1.1 最初设计。

如图1,首先创建一个Bevarage(饮料)的抽象类,店内所有的咖啡都继承这个类。description是成员变量,由子类设置,描述咖啡使用。getDescription()就是返回这个描述。cost()方法是抽象方法,由子类实现,计算价格使用。
最开始咖啡就有如下4个(对咖啡不太了解,中文名字错了不要在意):DarkRoast(超优深焙咖啡),Espresso(浓缩咖啡),Decaf(低卡咖啡),HouseBlend(混合咖啡)
在这里插入图片描述

但客人要求在咖啡里添加调料:Milk(奶),Soy(豆浆),Mocha(摩卡),每种调料都有单独的价钱,所以设计上又添加了这些,如图2。
在这里插入图片描述
这里我们可以看出问题,图2中只是列出了三种组合,我们可以想一下,这种组合是由很多种的,现在是4款咖啡,3种调料,在考虑到以后,可定会推出更多的咖啡和各种调料。这样维护起来,类会爆炸的,而且有的人还喜欢double份的Mocha,这样算的话类就会无穷无尽,而且物价是波动的,你还会修改价格,这样维护起来会死人的。

1.2 进一步改进

如图3,这次将调料加入Bevarage中的成员变量中,并加入相应的has和set方法,cost()方法现在提供实现,计算出调料的价格。再由子类加上咖啡的价格计算出最后的售价。
在这里插入图片描述

尽管这样,我们还可以看出问题:
(1)调料种类,价格变动,都会影响基类的cost()方法。
(2)基类很多方法对某一种咖啡可能带来不适应。
(3)顾客要了double份的Milk如何解决。

这就违背下面的设计原则。

设计原则:类应该对扩展开放,对修改关闭。


3.2 认识装饰者模式

1.如图4:以DarkRoast为例。顾客点了一杯DarkRoast,DarkRoast继承Beverage类,可以调用cost()方法计算价格。
在这里插入图片描述

2.如图5:顾客加了一份摩卡调料,这时建立一个Mocha的对象,包裹住DarkRoast。这里Mocha是装饰者,它的类型反应了装饰对象的类型,反应换句换说就是和装饰的对象的类型相一致。
在这里插入图片描述

3.如图6 ,顾客又加了一份奶泡调料,这时在创建一个Whip装饰者,装饰刚刚加了摩卡的DarkRoast的咖啡。
在这里插入图片描述

4.如图7 结账。调用最外层的cost()方法即可。
在这里插入图片描述

3.3 咖啡订单系统

3.3.1 类图

1.Bevarage是抽象类,其中cost()方法是抽象方法。
2.四种咖啡都继承Bevarage
3.新建一个调料抽象类CondimentDecorator,四种调料均继承此抽象类。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wBt8eMPQ-1580634442780)(3-8.png "图片3-8")]

3.3.2 代码实现

1.Bevarage和四种咖啡。

public abstract class Beverage {
    String description = "原味 咖啡";

    public String getDescription() {
        return description;
    }

    public abstract double cost();
}

public class DarkRoast extends Beverage {
    public DarkRoast() {
        description = "DarkRoast";
    }

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


public class Espresso extends Beverage {

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

    public double cost() {
        return 1.99;
    }
}


public class Decaf extends Beverage {
    public Decaf() {
        description = "Decaf";
    }

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


public class HouseBlend extends Beverage {

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

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

2.抽象类CondimentDecorator和3种调料。

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


public class Mocha extends CondimentDecorator {
    Beverage beverage;

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

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

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

public class Soy extends CondimentDecorator {
    Beverage beverage;

    public Soy(Beverage beverage) {
        this.beverage = beverage;
    }

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

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

public class Whip extends CondimentDecorator {

    Beverage beverage;

    public Whip(Beverage beverage) {
        this.beverage = beverage;
    }

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

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

3.测试代码。

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

        Beverage beverage1 = new DarkRoast();
        beverage1 = new Mocha(beverage1);
        beverage1 = new Mocha(beverage1);
        beverage1 = new Whip(beverage1);
        System.out.println(beverage1.getDescription() + " $" + beverage1.cost());

        Beverage beverage2 = new HouseBlend();
        beverage2 = new Soy(beverage2);
        beverage2 = new Mocha(beverage2);
        beverage2 = new Whip(beverage2);
        System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!