装饰器模式(Decorator Pattern)

来源:互联网 发布:西安程序员工资 编辑:程序博客网 时间:2024/05/29 05:54

定义

装饰者模式:动态地将责任附加到对象身上。若要扩展功能,将要比继承更加灵活,更富有弹性。

设计原则

  1. 封装变化。
  2. 少用继承,多用组合。
  3. 针对接口编程,不针对实现编程,更易于维护和扩展,更有条理。
  4. 交互对象之间的松耦合设计,是程序更具有弹性。
  5. 对扩展开放,对修改关闭

结构图

这里写图片描述

组成对象

  • 抽象组件角色(Component):定义一个对象接口,以规范准备接受附加责任的对象,即可以给这些对象动态地添加职责。
  • 具体组件角色(ConcreteComponent) :被装饰者,定义一个将要被装饰增加功能的类。可以给这个类的对象添加一些职责。
  • 抽象装饰器(Decorator):维持一个指向构件Component对象的实例,并定义一个与抽象组件角色Component接口一致的接口。
  • 具体装饰器角色(ConcreteDecoratorA,B…):向组件添加职责。

重点

  1. 装饰者和被装饰者(真实对象)具有相同的超类
  2. 可以有一个或者多个装饰者包装一个对象
  3. 可以用装饰者对象替代真实对象,可以在运行是动态的装饰对象
  4. 装饰者可以在真实对象执行自己的行为前/后加上自己的行为,达到特定目的

典型案例

下面就根据head first设计模式书中的例子,来看看星巴兹店是如何卖咖啡的。在计算不同组合的订单如何计算最终价格,以及出现新的调料或者咖啡品种,如何在不修改原有的代码基础上扩展程序——对扩展开发,对修改关闭

来看一下最终设计的类结构图

这里写图片描述

案例中对应的角色
1. 抽象组件角色(Component):Beverage
2. 具体组件角色(ConcreteComponent):DarkRoast、Decaf、Espresso、HouseBlend
3. 抽象装饰器(Decorator):CondimentDecorator
4. 具体装饰器角色(ConcreteDecoratorA,B…):Mocha、Soy、Whip

参考代码

饮料抽象类——Beverage

/** * 饮料抽象类 * @author: Yang Gao * @date: 2017-4-6 下午2:45:31 * @version: 1.0 */public abstract class Beverage {    protected String description = "Unknow Beverage!";    public String getDescription() {        return description;    }    // 定义饮料的单价    public abstract double cost();}

具体实现类,真实对象,被装饰者,各种饮料类

/** * 饮料:深度烘焙 * @author: Yang Gao * @date: 2017-4-6 下午3:46:20 * @version: 1.0 */public class DarkRoast extends Beverage {    public DarkRoast() {        this.description = "DarkRoast";    }    public double cost() {        return .99;    }}
/** * 饮料:低咖啡因 * @author: Yang Gao * @date: 2017-4-6 下午2:51:22 * @version: 1.0 */public class Decaf extends Beverage {    public Decaf() {        this.description = "Decaf";    }    @Override    public double cost() {        return 1.99d;    }}
/** * 饮料:浓咖啡 * @author: Yang Gao * @date: 2017-4-6 下午2:51:22 * @version: 1.0 */public class Espresso extends Beverage {    public Espresso() {        this.description = "Espresso";    }    @Override    public double cost() {        return 1.99d;    }}
/** * 饮料:混合 * @author: Yang Gao * @date: 2017-4-6 下午3:47:58 * @version: 1.0 */public class HouseBlend extends Beverage {    public HouseBlend() {        this.description = "House Blend Coffee";    }    public double cost() {        return .89;    }}

装饰抽象类, 调料抽象类

/** * 调料抽象类:装饰饮料类 * @author: Yang Gao * @date: 2017-4-6 下午2:45:31 * @version: 1.0 */public abstract class CondimentDecorator extends Beverage{    protected Beverage beverage;    public CondimentDecorator(Beverage beverage){        this.beverage = beverage;    }    public abstract String getDescription();}

具体装饰者

/** * 调料:摩卡 * @author: Yang Gao * @date: 2017-4-6 下午2:53:53 * @version: 1.0 */public class Mocha extends CondimentDecorator {    public Mocha(Beverage beverage) {        super(beverage);    }    @Override    public String getDescription() {        return super.beverage.getDescription() + ", Mocha";    }    @Override    public double cost() {        return .2d + super.beverage.cost();    }}
/** * 调料:豆浆 * @author: Yang Gao * @date: 2017-4-6 下午2:53:53 * @version: 1.0 */public class Soy extends CondimentDecorator {    public Soy(Beverage beverage) {        super(beverage);    }    @Override    public String getDescription() {        return super.beverage.getDescription() + ", Soy";    }    @Override    public double cost() {        return .15d + super.beverage.cost();    }}
/** * 调料:奶泡 * @author: Yang Gao * @date: 2017-4-6 下午2:53:53 * @version: 1.0 */public class Whip extends CondimentDecorator {    public Whip(Beverage berevage) {        super(berevage);    }    @Override    public String getDescription() {        return super.beverage.getDescription() + ", Whip";    }    @Override    public double cost() {        return .1d + super.beverage.cost();    }}

客户端测试类

/** * 咖啡店 * @author: Yang Gao * @date: 2017-4-6 下午2:57:20 * @version: 1.0 */public class StarbuzzCoffee {    public static void main(String[] args) {        // 1.来一杯浓咖啡        Espresso beverage = new Espresso();        System.out.println("一杯浓咖啡:" + beverage.getDescription() + ",  $" + beverage.cost());        // 2.来一杯双倍摩卡奶泡深度烘焙        Beverage beverage2 = new DarkRoast();        beverage2 = new Mocha(beverage2);        beverage2 = new Mocha(beverage2);        beverage2 = new Whip(beverage2);        System.out.println("一杯双倍摩卡奶泡深度烘焙:" + beverage2.getDescription() + ",  $" + beverage2.cost());        // 3.来一杯摩卡奶泡豆浆混合        Beverage beverage3 = new HouseBlend();        beverage3 = new Soy(beverage3);        beverage3 = new Mocha(beverage3);        beverage3 = new Whip(beverage3);        System.out.println("一杯摩卡奶泡豆浆浓混合:" + beverage3.getDescription() + ",  $" + beverage3.cost());       }

运行结果

这里写图片描述

0 0