《HeadFirst设计模式》读书笔记-第3章-装饰者模式
2017-03-28 23:05
323 查看
定义
装饰者模式(decorator pattern)动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。从上面的类图可以看出,装饰者(ConcreteDecoratorA)和被装饰者(ConcreteComponent)具有相同的超类型(Component)。在这里,我们利用继承达到“类型匹配”,而不是利用继承获得行为。由于装饰者和被装饰者有相同的类型,所以装饰者能够取代被装饰者。通过将装饰者和被装饰者组合,来获得新的行为。
代码实现
下面以星巴兹咖啡为例来说明装饰者模式的实现。咖啡有不同的类型,还可以加入不同的调料,咖啡类型和调料的组合会形成非常多的咖啡,如果客户每点一种咖啡就用一种类来表示的话,那么会有大量的类,而且不利于复用和变化。下面给出使用装饰者模式实现的类图。总体的思想是,咖啡类型对应具体的组件,每一种调料作为一种装饰者对不同的咖啡类型进行装饰,比如,客户要一份深焙咖啡加两份摩卡,一份奶泡,就可以用下面代码得到,首先用摩卡调料装饰者对深焙咖啡装饰,在用摩卡装饰者装饰一次,最后使用奶泡装饰者装饰一次来得到客户需要的咖啡。这样做的好处是,调料类和咖啡类型对应的类都复用的,如果需要调整价格的话,只要改一处即可,通过使用不同的装饰者,就可以得到不同的咖啡满足不同客户需要。
Beverage beverage2 = new DarkRoast(); // 深焙咖啡 beverage2 = new Mocha(beverage2); // 摩卡装饰者 beverage2 = new Mocha(beverage2); beverage2 = new Whip(beverage2); // 奶泡装饰者
定义抽象组件类,作为具体组件类和调料类的父类。
public abstract class Beverage { String description = "Unknown Beverage"; public String getDescription() { return description; } public abstract double cost(); }
定义具体的组件类,代表不同的咖啡类型。
// 综合咖啡 public class HouseBlend extends Beverage { public HouseBlend() { description = "House Blend Coffee"; } public double cost() { return .89; } }
// 深焙咖啡 public class DarkRoast extends Beverage { public DarkRoast() { description = "Dark Roast Coffee"; } public double cost() { return .99; } }
// 浓缩咖啡 public class Espresso extends Beverage { public Espresso() { description = "Espresso"; } public double cost() { return 1.99; } }
// 低咖啡因咖啡 public class Decaf extends Beverage { public Decaf() { description = "Decaf Coffee"; } public double cost() { return 1.05; } }
定义装饰者抽象类。
public abstract class CondimentDecorator extends Beverage { public abstract String getDescription(); }
定义具体装饰者类,代表各种咖啡调料。
// 牛奶调料 public class Milk extends CondimentDecorator { // 被装饰者,即具体组件 // 因为被装饰者和装饰者的基类都是Beverage类型,所以可以用Beverage类型表示 Beverage beverage; public Milk(Beverage beverage) { this.beverage = beverage; } // 描述说明 // 在被装饰者的基础上,加上装饰者的描述 public String getDescription() { return beverage.getDescription() + ", Milk"; } // 价格 // 在被装饰者的基础上,加上装饰者的价格 public double cost() { return .10 + beverage.cost(); } }
// 摩卡调料 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(); } }
// 豆浆调料 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(); } }
// 奶泡调料 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(); } }
测试驱动代码,也是客户代码,
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 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()); } }
现实世界中,Java I/O大量地使用了装饰者模式,笔者精心整理了下面的两种图,Java I/O的设计了大量的小类,每个小类完成特定的功能,通过层层的装饰,最后可以达到强大的功能。比如下面的代码实现了从文件”input.txt”读入数据的功能,同时使用了缓冲机制:
DataInputStream din = new DataInputStream( new BufferedInputStream( new FileInputStream("input.txt")));
JAVA I/O中输入输出字节流的类图:
JAVA I/O中输入输出Unicode字符流的类图:
本章金句
利用继承设计子类的行为,是在编译时静态决定的,而且所有的子类都会继承到相同的行为利用组合的做法扩展对象的行为时,可以在运行时动态地进行扩展
利用组合(composition)和委托(delegation)可以在运行时动态地给已经存在的代码加上新的行为
装饰者和被装饰者具有相同的超类型
装饰者模式意味着一群装饰者类,你可以用一个或者多个装饰者包装一个对象
装饰者可以在所委托被装饰者的行为之前或者之后,加上自己的行为,以达到特定的目的。
在装饰者模式的设计中,利用继承是为了达到“类型匹配”,而不是为了继承相同行为。利用装饰者和被装饰者之间的组合,来获得新的行为
装饰者通常是用其他工厂或者生成器这样的模式创建的
装饰者会导致设计中出现许多小对象,如果过度使用,会让程序变得很复杂
装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型
相关文章推荐
- HeadFirst设计模式_读书笔记_003_装饰者模式
- 《ERP从内部集成起步》读书笔记——第3章 用信息集成的观念理解MRP到ERP II 3.3ERP—企业资源计划—3.3ERP的管理模式—协同商务
- 【读书笔记】HeadFirst设计模式——命令模式简述
- 《HeadFirst设计模式》读书笔记-第1章-策略模式
- 《HeadFirst设计模式》读书笔记-第6章-命令模式
- 《HeadFirst设计模式》读书笔记-第5章-单例模式
- 设计模式-读书笔记2(第3章)
- HeadFirst设计模式_读书笔记_004_单例模式
- 【设计模式】《Head First 设计模式》读书笔记——装饰者模式
- 装饰者模式Decorator – 学习HeadFirst设计模式记录
- HeadFirst设计模式_读书笔记_002_观察者模式
- 【读书笔记】HeadFirst设计模式——装饰者和适配器的区别
- 《设计模式》读书笔记:装饰者模式
- 【HeadFirst设计模式】装饰者模式
- 设计模式读书笔记----装饰者模式
- 《HeadFirst设计模式》学习笔记2-装饰者模式
- 【读书笔记】HeadFirst设计模式——单件不简单:详述实现Singleton模式需要考虑的方方面面
- 读书笔记3:Head First设计模式——装饰者模式
- HeadFirst设计模式 之 C++实现(三):Decorator(装饰者模式)
- 读headFirst设计模式 - 装饰者模式