Java 设计模式之装饰模式(八)

一、前言

本篇主题为结构型模式中的第三个模式–装饰模式。上篇 Java 设计模式主题为《Java 设计模式之桥接模式(七)》

二、简单介绍

# 2.1 定义

装饰(Decorator)模式又叫做包装模式,其功能是动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活,是继承关系的一个替换方案。

# 2.2 参与角色

  1. Component:定义一个对象接口,可以给这些对象动态地添加职责。
  2. ConcreteComponent:定义一个对象,可以给这个对象添加一些职责。
  3. Decorator:维持一个指向 Component 对象的指针,并定义一个与 Component 接口一致的接口。
  4. ConcreteDecorator:向组件添加职责。

# 2.3 应用场景

  1. 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
  2. 当不能采用生成子类的方法进行扩充时。

三、实现方式

我们以人的打扮为例。人打扮需要穿衣,穿裤,穿鞋子。代码表示如下:

Person 类:

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
复制代码public class Person {



private String name;



public Person(String name) {

this.name = name;

}



public void putOnClothes() {

System.out.println(this.name + "穿衣服");

}



public void putOnTrousers() {

System.out.println(this.name + "穿裤子");

}



public void putOnShoes() {

System.out.println(this.name + "穿鞋子");

}

}

客户端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
复制代码public class Client {



public static void main(String[] args) {



Person person = new Person("小白");



person.putOnClothes();

person.putOnTrousers();

person.putOnShoes();

}

}

打印:

1
2
3
4
5
复制代码小白穿衣服

小白穿裤子

小白穿鞋子

上述代码很简单,但是扩展性不好。当我们需要添加打领带、戴手表的行为时,需要修改 Person 类,违背了开放封闭原则。

因此,我们需要将人和打扮的行为抽离出来:

Person 类:

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
复制代码public class Person {



private String name;



public Person(String name) {

this.name = name;

}



public String getName() {

return name;

}



}

打扮类:

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
62
63
复制代码public abstract class DressUp {



public abstract void dressup(Person person);

}





class ClothesDressUp extends DressUp {



@Override

public void dressup(Person person) {

System.out.println(person.getName() + "穿衣服");

}



}



class TrousersDressUp extends DressUp {



@Override

public void dressup(Person person) {

System.out.println(person.getName() + "穿裤子");

}



}



class ShoesDressUp extends DressUp {



@Override

public void dressup(Person person) {

System.out.println(person.getName() + "穿鞋子");

}



}

客户端:

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
复制代码public class Client {



public static void main(String[] args) {

Person person = new Person("小白");



DressUp du1 = new ClothesDressUp();

du1.dressup(person);



DressUp du2 = new TrousersDressUp();

du2.dressup(person);



DressUp du3 = new ShoesDressUp();

du3.dressup(person);

}

}

执行结果与上文的一致。现在,当我们添加新的打扮行为时,只需新增 DressUp 的子类即可。

但是,上边的代码没有封装性,每打扮一次都要调用 dressup 方法一次,就感觉人是光着身在公共场合进行打扮穿衣、穿鞋。因此,我们需要一种模式将这些打扮的细节封装起来,就像建造者模式一样。

不过,此次的需求不能使用建造者模式。因为建造者模式封装过程/细节是一个固定的顺序/模式,而当前需求是人的打扮,打扮的行为是多种多样的,如:穿衣穿裤、穿衣打领带、穿鞋戴手表等。

这样就引出了本章的主题–装饰模式:

Person 接口与实现类(Component 和 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
复制代码public interface Person {



public void decorate();

}



class Man implements Person {



@Override

public void decorate() {

System.out.println("男人打扮");

}



}

装饰类(Decorator 和 ConcreteDecorator):

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
复制代码public class Decorator implements Person {



private Person person;



public Decorator(Person person) {

this.person = person;

}



@Override

public void decorate() {

this.person.decorate();

}



}



class ClothesDecorator extends Decorator {



public ClothesDecorator(Person person) {

super(person);

}



public void decorate() {

super.decorate();

System.out.println("穿衣服");

}

}



class TrousersDecorator extends Decorator {



public TrousersDecorator(Person person) {

super(person);

}



public void decorate() {

super.decorate();

System.out.println("穿裤子");

}

}



class ShoesDecorator extends Decorator {



public ShoesDecorator(Person person) {

super(person);

}



public void decorate() {

super.decorate();

System.out.println("穿鞋子");

}

}

客户端:

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
复制代码public class Client {



public static void main(String[] args) {



Person person = new Man();



Person decorator = new Decorator(person);



System.out.println("======第一种打扮=======");



ClothesDecorator cd = new ClothesDecorator(decorator);



TrousersDecorator td = new TrousersDecorator(cd);



td.decorate();



System.out.println("======第二种打扮=======");



ShoesDecorator sd = new ShoesDecorator(person);



sd.decorate();

}

}

打印:

1
2
3
4
5
6
7
8
9
10
11
12
13
复制代码======第一种打扮=======

男人打扮

穿衣服

穿裤子

======第二种打扮=======

男人打扮

穿鞋子

总结:装饰模式有效地把类的核心职责和装饰功能区分开来,而且去除了相关类的重复的装饰逻辑。

UML 类图表示如下:

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%