浅谈Java设计模式系列0x08---装饰器模式

浅谈Java设计模式系列0x06—适配器模式
浅谈Java设计模式系列0x07—桥接模式

上次我给大家介绍了桥接模式,它是一个非常实用的设计模式;
本次再给大家介绍一个结构型模式—–装饰器模式;

装饰器是什么鬼

就像装饰我们的汽车,房间一样,在设计模式中,装饰器模式就是允许我们为现有的对象添加新的功能或特性,而不必去修改原有的代码;
装饰器模式是通过组合的方式实现对象功能或特性的扩展,这相比继承更加的灵活;

模式结构

  • 抽象构件(Component) : 它是具体构件(ConcreteComponent)抽象装饰类(Decorator)的共同父类,声明了具体构件中实现的业务方法;
  • 具体构件(ConcreteComponent) : 它是抽象构件类(Component)的子类,定义具体的构件对象,并实现抽象构件类中定义的方法;
  • 抽象装饰类(Decorator) : 它也是抽象构件类(Component)的子类,用于给具体构件增加职责,具体职责在其子类中实现;
  • 具体装饰类(ConcreteDecorator) : 它是抽象装饰类(Decorator)的子类,负责向构件添加新的职责,扩充对象的行为;

什么时候能用

在以下情况下可以使用装饰模式:

  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责;
  • 需要动态地给一个对象增加功能,这些功能也可以动态地被撤销;
  • …..

代码示例

本次我们的例子还是熟悉的手机例子,我们对一台ApplePhonecallmessage功能进行装饰;
代码参考

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
/**
* 抽象构件(Component) 抽象手机构件
*/

public interface Phone {
// 手机构件的业务方法,打电话
void call();
// 手机构件的业务方法,发信息
void message();
}
/**
* 具体的构件(ConcreteComponent)
*/

public class ApplePhone implements Phone {
@Override
public void call() {
System.out.println("apple phone is calling...");
}

@Override
public void message() {
System.out.println("apple phone is sending message...");
}
}

/**
* 抽象装饰类(Decorator)
* 在 PhoneDecorator 中并未真正实现 call() 方法,而只是调用原有 phone 对象的 call() 方法
* 它没有真正实施装饰,而是提供一个统一的接口,将具体装饰过程交给子类完成.
*/

public class PhoneDecorator implements Phone {
//持有一个抽象构件实例的引用
private Phone phone;

//注入抽象构件类型的对象
public PhoneDecorator(Phone phone) {
this.phone = phone;
}
@Override
public void call() {
//调用原有的业务方法
this.phone.call();
}
@Override
public void message() {
this.phone.message();
}
}

/**
* 具体的装饰类(ConcreteComponent)
* 在具体装饰类中可以调用到抽象装饰类的方法,同时可以定义新的业务方法
*/

public class FaceTimeDecorator extends PhoneDecorator {
public FaceTimeDecorator(Phone phone) {
super(phone);
}

@Override
public void call() {
super.call();//调用原有的业务方法
callWithFaceTime();//调用新增的业务方法
}

//新增的业务方法,
public void callWithFaceTime(){
System.out.println("this call is powered by FaceTime...");
}
}

/**
* 具体的装饰类(ConcreteComponent)
* 在具体装饰类中可以调用到抽象装饰类的方法,同时可以定义新的业务方法
*/

public class IMessageDecorator extends PhoneDecorator {
public IMessageDecorator(Phone phone) {
super(phone);
}

@Override
public void message() {
super.message();//调用原有的业务方法
messageWithIMessage();//调用新增的业务方法
}
//新增的业务方法,
public void messageWithIMessage(){
System.out.println("this message is powered by IMessage...");
}
}

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 测试类
* 在具体装饰类中可以调用到抽象装饰类的方法,同时可以定义新的业务方法
*/

public class Client {

public static void main(String[] args) {
Phone phone=new ApplePhone();
phone.call();
phone.message();
System.out.println("--------------------------------------");
phone = new FaceTimeDecorator(phone);//第一次装饰,对call()进行装饰
phone = new IMessageDecorator(phone);//第二次装饰,对message()进行装饰
//也可以使用如下方法进行多次嵌套装饰
//phone = new IMessageDecorator(new FaceTimeDecorator(phone));
phone.call();
phone.message();

}
}

运行结果

1
2
3
4
5
6
7
apple phone is calling...
apple phone is sending message...
--------------------------------------
apple phone is calling...
this call is powered by FaceTime...
apple phone is sending message...
this message is powered by IMessage...

总结

装饰模式通过动态的方式扩展一个对象的功能,并且具体构件类和具体装饰类可以独立的变化,通过不同的组合方式可以创造很多不同的行为;
但是装饰模式在系统设计时会产生很多小对象,而且经过多次装饰的对象出错时,查错会变得复杂繁琐;

参考

扩展系统功能——装饰模式(二)