Android Tech And Thoughts.

Decorator Pattern

Word count: 1.2kReading time: 4 min
2019/12/18 Share

装饰者模式的作用主要在于控制类的数量。其核心思想是利用组合来代替继承,从而动态地扩展类的功能。

后者更好地控制了类的数量,假设需要扩展 n 个功能,那么继承所需的类的数量为 n! 数量级
而采用装饰着模式则为 O(n)

先给出以下结论,带着为什么来思考:

  • 装饰者和被装饰对象有相同的超类型(接口或者类都ok)
  • 可以使用一个或者多个装饰者包装一个对象
  • 既然装饰者和被装饰者具有相同的超类型,所以在任何需要原始对象(被包装的)的场合,可以用装饰过的对象代替它
  • 装饰者可以在所委托被装饰者的行为之前/或之后,加上自己的行为,以达到特定的目的
  • 对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢地装饰者来装饰对象

如何装饰者模式:

  • 把类的核心职责和装饰功能区分开来
  • 装饰者可以添加新的方法,但是能继续被装饰的方法只能是共同超类中的接口方法

实例探究Decorator

Head First Design Pattern 中谈到一个非常适合使用装饰者模式的案例,就是饮料店的案例,我们先来看一下需求:
有一家新开的饮料店,现在我们需要为订单系统设计相应的类,以使得我们可以计算相应的价格。

我们可以这样设计

1
public interface Beverage{
2
	double cost();
3
}
4
5
// 基础类
6
public class BaseBeverage impelments Beverage{
7
	@Override
8
	public double cost(){
9
		return 10;
10
	}
11
}
12
13
//装饰类
14
public class Decorator implements Beverage{
15
	private Beverage bev;
16
	
17
	public Decorator(Beverage bev){
18
		this.bev = bev;
19
	}
20
	@Override
21
	public double cost(){
22
		return super.cost();
23
	}
24
		
25
}
26
27
//具体装饰类
28
-------------------------------------------
29
public Moca extends Decorator{
30
	
31
	@Override
32
	public double cost(){
33
		return super.cost()+5;
34
	}
35
}
36
37
public Kapc extends Decorator{
38
	@Override
39
	public double cost(){
40
		return super.cost()+4.5;
41
	}
42
}
43
.....

综合上面的,我们可以发现严格的装饰者模式遵循下面的类结构

restrictDecorator .png

注: Concreat意味实际的,完全的,表示是一个实体类,而非抽象类或者接口

装饰者模式的一些变化

1.装饰者模式的简化

大多数情况下,装饰者模式的实现都要比上面给出的例子要简单
可以考虑去掉抽象的Component类(接口),把 Decorator 作为一个ConcreatComponent子类,如下图:
simpleDecorator.png

还可以将Decorator和ConcreteDecorator类的责任合并成一个类
simpleDecorator2.png

2.透明性的要求

装饰者模式对客户端的透明性,要求程序不要声明一个ConcreteComponet类型的变量,而应当声明一个Component类型的变量。用饮料的例子来说,不要声明一个 BaseBeverage或者更具体的Decorator类,而应当声明一个Beverage类型。

1
Beverage bev = new Basebevrage();
2
Beverage moca = new Moca(bev);

而不是

1
Moca moca = new Moca(bev);

半透明的装饰者模式

然而,纯粹的装饰者模式不常见,装饰者模式的用意在不改变接口的前提下,增强所考虑的类的性能。在增强性能的时候,往往需要建立新的公开的方法。比如说在饮料里,Moca咖啡可以赠送一张电影票。

1
public Moca extends Decorator{
2
	@Override
3
	public double cost(){
4
		return super.cost()+5;
5
	}
6
	
7
	// 重点关注这个新增的功能
8
	public String getMovieCode(){
9
		String moviewCode = ...
10
		return movieCode;
11
	}
12
}

允许装饰模式改变接口,增加新的方法,这意味着客户端可以声明ConcreteDecorator类型的变量,从而可以调用ConcreteDecorator类中才有的方法:

1
Moca moca = new Moca(new Beverage());
2
System.out.println(moca.getMovieCode());

半透明的装饰者模式也称为半装饰,它介于装饰者模式和适配器模式之间,也称为半适配器模式。
vs.png

装饰者模式的优点:

  • 装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性,继承是静态的,而装饰则是动态的
  • 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合

装饰模式的缺点:
由于使用装饰模式,会产生比继承关系更多的对象。更多的对象使得查错更为困难,特别是这些对象看上去都很像

Thanks:

Java与模式之装饰模式
设计模式之装饰者模式
调料案例

CATALOG
  1. 1. 实例探究Decorator
  2. 2. 装饰者模式的一些变化
    1. 2.1. 1.装饰者模式的简化
    2. 2.2. 2.透明性的要求
      1. 2.2.1. 半透明的装饰者模式
    3. 2.3. Thanks: