您的位置:首页 > 编程语言 > Java开发

《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)可以在运行时动态地给已经存在的代码加上新的行为

装饰者和被装饰者具有相同的超类型

装饰者模式意味着一群装饰者类,你可以用一个或者多个装饰者包装一个对象

装饰者可以在所委托被装饰者的行为之前或者之后,加上自己的行为,以达到特定的目的。

在装饰者模式的设计中,利用继承是为了达到“类型匹配”,而不是为了继承相同行为。利用装饰者和被装饰者之间的组合,来获得新的行为

装饰者通常是用其他工厂或者生成器这样的模式创建的

装饰者会导致设计中出现许多小对象,如果过度使用,会让程序变得很复杂

装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息