【设计模式】HeadFirst设计模式(三):装饰者(Decorator)模式

今天就来写一下装饰者模式,该软考了,也该实习了,感觉心态静不下来,设计模式都是一些简单的小例子,但是看了这么久连简单的了解还没有完全搞定,深感惭愧,还是要安静下来,书中才有颜如玉~ ~ ~不扯了,下边进入正题

一、装饰者模式定义

在不修改原类的基础上,动态地扩展原来的对象的功能,装饰者提供了比继承更有弹性的替代方案:通过创建一个包装对象(装饰对象),来包裹真实的对象

二、装饰者模式特点

(1) 装饰者和被装饰者有相同的超类型
(2) 可以用一个或者多个装饰者包装一个对象
(3) 因为装饰者和被装饰者有相同超类型,则可以在任何需要原始对象(被包装的对象)的场合,用装饰过的对象代替它
(4) 装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的(注意加粗部分)
(5) 对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用某装饰者来装饰对象

三、装饰者模式的具体实现——设计咖啡店的订单管理系统

1、首先看下咖啡店原本的类设计:

Beverage类(抽象类):属性description由子类设置

每个子类实现cost抽象方法,返回各自价格


当然,在购买咖啡的时候,可以要求在其中加入各种调料:豆浆(Soy)、摩卡(Mocha)、奶泡(Whip)等等,咖啡店会根据加入调料收取不同的费用,所以订单系统需要考虑这些调料部分

解决方法(1):所以我们可以这样做,设计出这些类:

摩卡和奶泡深焙咖啡类、摩卡深焙咖啡类、豆浆浓缩咖啡类等等

可以看出来,我们根据调料和咖啡的种类要用排列组合计算到底需要多少类了。这简直就是”类爆炸“,制造了维护的噩梦

解决方法(2):重新设计Beverage(饮料)类如下


重新设计后的Beverage不再是一个抽象类而是一个具体类:

public class Beverage {
    String description;
    boolean milk;
    boolean soy;
    boolean mocha;
    boolean whip;
    double milkCost = 1.0;
    double soyCost = 2.0;
    double mochaCost = 3.0;
    double whipCost = 4.0;
    //获得描述
    public String getDescription(){
        return description;
    }
    //得到调料价格
    public double cost(){
        double condimentCost = 0.0;
        if(isMilk()){
            condimentCost += milkCost;
        }
        if(isMocha()){
            condimentCost += mochaCost;
        }
        if(isSoy()){
            condimentCost += soyCost;
        }
        if(isWhip()){
            condimentCost += whipCost;
        }
        return condimentCost;
    }

    //省略milk、mocha、soy、whip的setter和getter方法
}
然后,实现DarkRoast(深焙咖啡类):

public class DarkRoast extends Beverage {
    public DarkRoast(){
        description = "我是深焙咖啡";
    }
    public double cost(){
        return 1.99+super.cost();
    }
}
然后我们写一个main函数:

public class Main {
    public static void main(String[] args) {
        //我想要一个加奶的深焙咖啡
        T t = new T1();
        t.setMilk(true);
        System.out.println("加奶的深焙咖啡价格:"+t.cost());
    }
}
打印出来结果:加奶的深焙咖啡价格:2.99 
如此,我们就可以实现我们想要的了。但是,这里有一个很严重的问题:如果我们需要增加一个配料的话,我们就需要继续修改这个Beverage类了,这违反了”扩展开放,修改关闭的开—闭设计原则“。我们如何改良? 

2、利用装饰者模式对系统进行重新构造 


(1) 如果顾客想要摩卡和奶泡深焙咖啡,那么我们需要做的是 
① 拿一个深焙咖啡对象 
② 以摩卡对象装饰它 
③ 以奶泡对象装饰它 
④ 调用cost方法,并依赖委托将调料的价格加上去 
步骤: 


等到算钱的时候只需要调用最外层Whip的cost方法就可以办到 

(2) 定义装饰者模式 


3、使用装饰者模式实现咖啡店的订单系统: 


Beverage.java

public abstract class Beverage {
    protected String description = "Unknown Beverage";

    public String getDescription() {
        return description;
    }

    public abstract double cost();
}

HouseBlend.java

//浓缩咖啡
public class HouseBlend extends Beverage {

    public HouseBlend() {
        description = "House Blend Coffee";
    }

    public double cost() {
        return .89;
    }
}

DarkRoast.java

//深焙咖啡
public class DarkRoast extends Beverage {

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

    public double cost() {
        return .99;
    }
}

Epresso.java

//浓缩咖啡
public class Espresso extends Beverage {

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

    public double cost() {
        return 1.99;
    }
}

CondimentDecorator.java

//配料类的超类
public abstract class CondimentDecorator extends Beverage {
    public abstract String getDescription();
}

Mocha.java

//摩卡(配料)
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 .20 + beverage.cost();
    }
}

Soy.java

//豆浆(配料)
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 .15 + beverage.cost();
    }
}

Whip.java

//奶泡(配料)
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 .10 + beverage.cost();
    }
}

然后写一个简单的main函数:

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

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

        Beverage beverage3 = new HouseBlend();
        beverage3 = new Soy(beverage2);
        beverage3 = new Mocha(beverage2);
        beverage3 = new Whip(beverage2);
        System.out
                .println(beverage3.getDescription() + " $" + beverage3.cost());
    }


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值