5.[研磨设计模式笔记]装饰模式

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 );
     }
}

案例说明:

170404990.png

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  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流

170501449.png

InputStream就相当于装饰模式中的Component;

FileInputStream、ObjectInputStream、StringBufferInputStream这些对象都是直接继承InputStream,这些相当于装饰模式中的ConcreteComponent,是可以被装饰器装饰的对象;

FilterInputStream相当于装饰器模式中的Decorator,而它的子类DataInputStream、BufferedInputStream、LinkNumberInputStream和PushbackInputStream 相当于装饰器模式中的ConcreteDecorator。

装饰模式的优缺点:

优点:比继承更灵活、更容易复用功能、简化高层定义

缺点:会产生很多细粒度对象

4.思考

装饰模式的本质是:动态组合

动态是手段,组合才是目的。这里组合有两个意思,一个是动态功能的组合,也就是动态进行装饰器的组合;另一个是指对象组合,通过对象组合来实现为装饰对象透明的增加功能。

何时选用装饰模式模式

如果想:在不影响其他对象的情况下,以动态、透明的方式给对象添加职责,可以使用装饰模式。

如果:不适合使用子类来扩展的时候,可以使用装饰模式。










本文转自 LinkedKeeper 51CTO博客,原文链接:http://blog.51cto.com/sauron/1230136,如需转载请自行联系原作者
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值