设计模式--结构型:装饰模式

装饰模式:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比直接修改子类更加灵活

装饰模式 Decorator :也称为包装模式 Wrapper Pattern,常见于给某个对象添加功能而不是整个类。装饰模式可以修改对象的功能,而不用修改子类代码。代码中如果看到 Wrapper 结尾的类,通常是用了装饰模式的设计思路。
装饰模式通常用于动态和透明的扩展类的功能,特别是当系统维护中需要添加新功能,而这个功能是需要向旧类中添加新代码,而这个功能并不是旧类的主要职责或者核心功能。在这种场景下,使用装饰模式添加一个装饰类,在不破坏原有代码的基础上,动态的给对象添加或修改功能。

装饰模式 Decorator

类图结构

0055-Decorator-uml-classdiag.png

结构解析

  • Component
    抽象类,定义公共方法。
  • ConcreteComponent
    实现类,实现该方法。
  • Decorator
    抽象类,也是装饰类,类内部会指向一个 Component 实现类,形成组合关系,具体的 operation 都是传入的 Component 来实现的。
  • ConcreteDecorator
    实现类,除了调用 ConcreteComponent 对应的方法,通常会修改或增加功能。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// 1. Component
public abstract class Component {
public abstract void operation();
}

// 2. ConcreteComponent
public class ConcreteComponent extends Component{
@Override
public void operation() {
System.out.println("ConcreteComponent::operation.");
}
}

// 3. Decorator
public abstract class Decorator extends Component{
Component component;

public Decorator(Component component){
this.component = component;
}

@Override
public void operation() {
component.operation();
}
}

// 4. ConcreteDecorator
public class ConcreteDecorator extends Decorator{
public ConcreteDecorator(Component component) {
super(component);
}

@Override
public void operation() {
super.operation();
addBehavior();
}

private void addBehavior(){
System.out.println("ConcreteDecorator::addBehavior.");
}
}

// 5. Test
public class TestDecorator {
public static void main(String[] args) {
Component component = new ConcreteComponent();
Component decorator = new ConcreteDecorator(component);
component.operation();
System.out.println("##Decorator Pattern: add extra function
for component.##");
decorator.operation();
}
}

// 6. Result
ConcreteComponent::operation.
##Decorator Pattern: add extra function for component.##
ConcreteComponent::operation.
ConcreteDecorator::addBehavior.

Android 中经典的装饰模式

Android 中的 Context/ContextWraaper 就是经典的装饰模式。

类图结构

0055-decorator-Android_Context-uml-classdiag.png

类图解析

  • Context
    抽象类,定义了所有的公共方法。
  • ContextImpl
    实现类,实现了所有的方法。
  • ContextWrapper
    包装类,也是抽象类,使用组合结构引用了 ContextImpl
  • Activity
    包装类实现类,Activity, Service, Application 都继承了 ContextWrapper,这些子类动态添加或修改了 ContextImpl 的部分方法。

总结

装饰模式很容易和桥接模式、代理模式混淆,我们看下他们之间的区别以及装饰模式的优缺点。

装饰模式和桥接模式的区别

0055-decorator-bridge-classdiag-diff.png

类图结构有较大区别,从对比图中可以看出:

  • 结构维度
    桥接模式是不同维度的分类,属于平行结构;装饰模式是继承结构,在继承的基础上修改功能。
  • 是否继承
    桥接模式的两种维度没有继承关系,仅仅是组合关系(松耦合);而装饰模式除了组合还必须是继承关系(紧耦合),也就是 Decorator 继承并组合了 Component
  • 方法名是否一致
    桥接模式仅仅需要组合,所以方法名一般不同;装饰模式因为带有继承关系,所以装饰时重写方法,方法名相同。

装饰模式和代理模式的区别

  • 类图结构基本一致
  • override 重写方法后的侧重点不一样
    装饰器模式关注于在一个对象上动态的添加或修改方法;代理模式关注于控制对对象的访问,对是否执行实现类有决定权。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // 1. 装饰器模式
    @Override
    public void operation() {
    impl.operation();
    addBehavior();
    }

    // 2. 代理模式
    @Override
    public void operation() {
    if (hasOption()){
    impl.operation();
    } else {
    System.out.println("不符合选项。");
    }
    }

装饰模式和代理模式非常非常像,唯一的区别在与侧重点不一样:装饰模式侧重于修改功能,代理模式侧重于控制访问。

装饰模式优缺点

  • 优点
    可以通过一种动态的方式来扩展一个对象的功能,具体构件类与具体装饰类可以独立变化,原有代码无须改变,符合“开闭原则”。
  • 缺点
    使用装饰模式进行系统设计时将产生很多小对象,这些对象的区别在于它们之间相互连接的方式有所不同,而不是它们的类或者属性值有所不同,同时还将产生很多具体装饰类。

参考文档

0%