1.定义
动态的给一个对象添加一个额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
2.解决问题
——奖金计算
不用模式的解决方案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public
class
Prize {
public
double
calcPrize(String user, Date begin, Date end) {
double
prize =
0.0
;
// 计算当月业务奖金,所有人都会计算
prize =
this
.monthPrize(user, begin, end);
// 计算累计奖金
prize +=
this
.calcPrize(user, begin, end);
// 需要判断该人员是普通人员还是业务经理,团队奖金只有业务经理才有
if
(
this
.isManager(user)) {
prize +=
this
.groupPrize(user, begin, end);
}
return
prize;
}
private
double
groupPrize(String user, Date begin, Date end) {
return
0
;
}
private
boolean
isManager(String user) {
return
false
;
}
private
double
monthPrize(String user, Date begin, Date end) {
return
0
;
}
}
|
使用装饰模式来解决问题
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
|
public
abstract
class
Component {
public
abstract
double
calcPrize(String user, Date begin, Date end);
}
public
abstract
class
Decorator
extends
Component {
protected
Component c;
public
Decorator(Component c) {
super
();
this
.c = c;
}
public
double
calcPrize(String user, Date begin, Date end) {
// 转调组件对象的方法
return
c.calcPrize(user, begin, end);
}
}
public
class
MonthPrizeDecorator
extends
Decorator {
public
MonthPrizeDecorator(Component c) {
super
(c);
}
public
double
calcPrize(String user, Date begin, Date end) {
// 先获取前面运算出来的奖金
double
money =
super
.calcPrize(user, begin, end);
// 然后计算当月业务奖金
double
prize =
0.0
;
return
money + prize;
}
}
public
class
SumPrizeDecorator
extends
Decorator {
public
SumPrizeDecorator(Component c) {
super
(c);
}
public
double
calcPrize(String user, Date begin, Date end) {
// 先获取前面运算出来的奖金
double
money =
super
.calcPrize(user, begin, end);
// 然后计算累计奖金
double
prize =
1000000
*
0.001
;
return
money + prize;
}
}
public
class
Client {
public
static
void
main(String[] args) {
Component c1 =
new
ConcreteComponent();
Decorator d1 =
new
MonthPrizeDecorator(c1);
Decorator d2 =
new
SumPrizeDecorator(d1);
double
userA = d1.calcPrize(
"a"
,
null
,
null
);
double
userB = d2.calcPrize(
"b"
,
null
,
null
);
}
}
|
案例说明:
3.模式讲解
由于奖金的计算方式经常发生变动,几乎每个季度都有小调整,每年都有大调整,这要求软件实现要足够灵活,能够很快进行相应的调整和修改,否则就不能满足实际业务的需要。把问题抽象以下:设若有一个计算奖金的对象,现在需要能够灵活的给它增加和减少功能,还需要能够动态的组合功能,每个功能就相当于在计算奖金的某个部分。
则问题就是:如何能透明地给一个对象增加功能,并实现功能的动态组合。
解决思路
所谓透明地给一个对象增加功能,即给一个对象增加功能,但不能让这个对象知道,也就不是不去改动这个对象,而实现给一个对象透明的增加功能,这就实现了功能的动态组合。
实现透明地给一个对象增加功能,即要扩展对象功能,可使用继承。
为了能够实现和原来使用被装饰对象的代码无缝结合,通过顶一个抽象类,让这个类实现与被装饰对象相同的接口,然后在具体实现类中,转调被装饰的独享,在转调前后添加新的功能,这就实现了给装饰对象增加功能。
在转调的时候,如果觉得被装饰对象的功能不再被需要,还可以直接替换,也就是不在转调,而是在装饰杜相忠完成全新的实现。
示例代码
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
|
public
abstract
class
Component {
public
abstract
void
operation();
}
public
class
ConcreteComponent
extends
Component {
public
void
operation() {
// 相应的功能处理
}
}
public
abstract
class
Decorator
extends
Component {
protected
Component component;
public
Decorator(Component component) {
super
();
this
.component = component;
}
public
void
operation() {
// 转发请求给组件独享,可以在转发前后执行一些附加动作
component.operation();
}
}
public
class
ConcreteDecoratorA
extends
Decorator {
public
ConcreteDecoratorA(Component component) {
super
(component);
}
private
String addedState;
public
void
operation() {
// 调用父类的方法,可以在调用前后执行一些附加动作
// 在这里进行处理的时候,可以使用添加的状态
super
.operation();
}
}
public
class
ConcreteDecoratorB
extends
Decorator {
public
ConcreteDecoratorB(Component component) {
super
(component);
}
private
void
addBehavior() {
// 需要添加的职责实现
}
public
void
operation() {
// 调用父类的方法,可以在调用前后执行一些附加动作
super
.operation();
this
.addBehavior();
}
}
|
应用范围
装饰模式能够实现动态添加,是从一个对象外部来给对象添加功能,相当于改变了对象的外观。当装饰后,从外部使用系统的角度,就不再是使用原来是的那个类,而是使用被一系列装饰器包装过后的对象。
对象组合
在面向对象的设计中,有一条基本规则就是"尽量使用对象组合,而不是继承"来扩展和复用功能。装饰模式就是这个规则。
假如有一个对象A,实现了a1方法,而C1对象想要扩展A的功能,给它增加一个c1的方法。
使用继承:
1
2
3
4
5
6
|
public
class
A {
public
void
a1() {}
}
public
class
C
extends
A {
public
void
c1() {}
}
|
使用对象组合:
1
2
3
4
5
6
7
|
public
class
C {
private
A a =
new
A();
public
void
a1() {
a.a1();
}
public
void
c1() {}
}
|
装饰器和组件类的关系
装饰器是用来修饰组件的,装饰器一定要实现和组件类一致的接口。组件类是不知道装饰器的存在的,装饰器为组件提那家功能是一种透明的包装。
装饰器的应用—— I/O流
InputStream就相当于装饰模式中的Component;
FileInputStream、ObjectInputStream、StringBufferInputStream这些对象都是直接继承InputStream,这些相当于装饰模式中的ConcreteComponent,是可以被装饰器装饰的对象;
FilterInputStream相当于装饰器模式中的Decorator,而它的子类DataInputStream、BufferedInputStream、LinkNumberInputStream和PushbackInputStream 相当于装饰器模式中的ConcreteDecorator。
装饰模式的优缺点:
优点:比继承更灵活、更容易复用功能、简化高层定义
缺点:会产生很多细粒度对象
4.思考
装饰模式的本质是:动态组合
动态是手段,组合才是目的。这里组合有两个意思,一个是动态功能的组合,也就是动态进行装饰器的组合;另一个是指对象组合,通过对象组合来实现为装饰对象透明的增加功能。
何时选用装饰模式模式
如果想:在不影响其他对象的情况下,以动态、透明的方式给对象添加职责,可以使用装饰模式。
如果:不适合使用子类来扩展的时候,可以使用装饰模式。