装饰者模式:动态地将责任附加到对象身上。若要扩展功能,将要比继承更加灵活,更富有弹性。
下面就根据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()); }运行结果