Download presentation
Presentation is loading. Please wait.
1
第八章 装饰者模式 欢迎饮用星巴兹(Starbuzz)咖啡 最初设计的订购系统(下页):
2
家庭混合咖啡 焦炒咖啡 无咖啡因咖啡 蒸馏咖啡
3
购买咖啡时,每一种咖啡中能添加一种或几种调料:steamed milk(蒸煮的牛奶), soy(酱油), mocha(摩卡,也称
为巧克力),和 whipped milk (加了甜点心的牛奶)。每一种调料都要收一点钱,星巴兹(Starbuzz)咖啡订购系统变成下面的样子(下页):
4
每个cost()方法计算咖啡及各种调料的价钱。
类爆炸! 每个cost()方法计算咖啡及各种调料的价钱。 从基类派生添加了各种调料的咖啡子类。
6
修改后的订购系统
7
修改后的订购系统怎么样?
8
这个设计的缺陷 如果调料的价格改变,我们需要修改现存的代码。 如果增加了新的调料,我们需要在基类增加新的方 法以及修改cost()方法。
我们也可能有新的饮料类型。一些饮料类型,例如, 冰茶(ice tea),现有的调料可能是不合适的。但是, 茶子类仍然后继承基类的调料方法。 如果客户需要双份mocha,怎么办呢?
9
开闭原则 我们的目的是允许类易于扩展,组合新的行为, 但不修改现有的代码。
10
会会装饰者模式 我们已经看到:附加调料的饮料定价模式,用继承表示是不合适的;在基类增加调料的实例变量和方法,对一些子类也是不合适的。
这里,我们试试:以饮料为主体,用调料“装饰”饮料。例如,如果客户需要Dark Roast(焦炒咖啡) ,添加Mocha(摩卡)和Whip(甜点心)。
11
会会装饰者模式(续) 我们可以: ① 取DarkRoast (焦炒咖啡)对象; 用Mocha (摩卡)对象装饰它;
用Whip (甜点心)对象装饰它; 调用cost()方法计算价格,总价格的计算需要委托。 但是,我们怎样装饰一个对象?又怎样委托?
12
用装饰者构造饮料订购系统 ① 从DarkRoast (焦炒咖啡)对象开始
13
客户需要Mocha (摩卡) ,所以,我们创建一个Mocha 对象,并用它包装DarkRoast (焦炒咖啡) 。
装饰者对象是“包装者”。
14
客户也需要Whip (甜点心) ,所以,我们也创建一个
Whip装饰者,并用它包装Mocha (摩卡) 。
15
现在为客户计算价格。我们调用最外层装饰者(Whip
甜点心)的cost()。Whip委托它所装饰的对象计算价格。 它获得了价格后,再累加Whip的价格。
16
目前做的… 装饰者和被装饰对象有相同的超类型; 可以用一个或多个装饰者包装一个对象; 任何时候需要原始对象(即被包装的对象),都可以用装
饰过的对象代替它。因为装饰者和被装饰者有相同的 超类型; 装饰者可以在所委托的被装饰者的行为之前与/或之后, 加上自己的行为,以达到特定的目的。 对象可以在任何时候被装饰,所以可以在运行时动态 地、不限量地使用装饰者来装饰对象。
17
装饰者模式定义
18
装饰者模式类图
19
装饰我们 的饮料
20
写星巴兹(Strbuzz)代码 我们从Beverage类开始,它与原设计是一样的:
public abstract class Beverage { String description = "Unknown Beverage"; public String getDescription() { return description; } public abstract double cost();
21
实现调料(装饰者)抽象类 public abstract class CondimentDecorator extends Beverage { public abstract String getDescription(); }
22
对饮料编码 public class Espresso extends Beverage { //蒸馏咖啡
public Espresso() { description = "Espresso"; } public double cost() { return 1.99;
23
对饮料编码(续) public class HouseBlend extends Beverage { //家庭混合咖啡
public HouseBlend() { description = "House Blend Coffee"; } public double cost() { return .89;
24
实现调料(装饰者)具体类 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 beverage.cost(); 描述不只是饮料,还要包括添加的调料。
25
订购星巴兹(Starbuzz)咖啡的测试代码
public class StarbuzzCoffee { 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 Whip(beverage2); // 添加甜点心 System.out.println(beverage2.getDescription() + " $" + beverage2.cost()); Beverage beverage3 = new HouseBlend(); // 家庭混合咖啡 beverage3 = new Soy(beverage3); // 添加酱油 beverage3 = new Mocha(beverage3); // 添加摩卡 beverage3 = new Whip(beverage3); // 添加甜点心 System.out.println(beverage3.getDescription() + " $" + beverage3.cost()); }
26
订购结果
27
真实世界的装饰者:Java I/O java.io包内的类太多了!其实,许多类都是装饰者。下面是一个典型的对象集合(下页):
28
真实世界的 装饰者: Java I/O(续)
29
Java I/O装饰类
Similar presentations