(java)从零开始之--装饰者设计模式

装饰者设计模式
简单定义:增强一个类的功能,而且还可以让这些装饰类互相装饰。

应用场景:当要在某个功能的基础上扩充功能,并且扩充的功能具有大量排列组合,通过继承关系会衍生出大量子类,这时候用装饰者模式来解决。

装饰者设计模式的步骤
1. 在装饰类的内部维护一个被装饰类的引用。
2. 让装饰类有一个共同的父类或者是父接口。

例如:人有一种行为叫“吃水果”,其中水果有4种:苹果、香蕉、鸭梨、橘子
现在有需求如下:
A类人行为:吃苹果
B类人行为:先吃苹果,再吃香蕉
C类人行为:先吃香蕉,再吃苹果
D类人行为:先吃橘子,后吃鸭梨

我们先用子类继承来实现:代码如下

 1 interface IEatFruit{
 2 public void eatFruit();
 3 }
 4 
 5 class PersonA implements IEatFruit{
 6 
 7   @Override
 8   public void eatFruit() {
 9     System.out.println("吃苹果"); 
10   }
11 
12 }
13 class PersonB implements IEatFruit{
14 
15 @Override
16   public void eatFruit() {
17     System.out.println("吃苹果"); 
18     System.out.println("吃香蕉"); 
19   }
20 
21 }
22 class PersonC implements IEatFruit{
23 
24   @Override
25   public void eatFruit() {
26     System.out.println("吃香蕉");
27     System.out.println("吃苹果"); 
28   }
29 
30 }
31 class PersonD implements IEatFruit{
32 
33   @Override
34   public void eatFruit() {
35     System.out.println("吃橘子");
36     System.out.println("吃鸭梨"); 
37   }
38 
39 }

这样当然是没问题的,每一类人对应new出来的对象 都可以实现对应的需求。
但是,当需求改为:
某类人行为:吃上面四种水果,并且要求有先后顺序
这样的排列组合有24种....
这样你还会用继承去做吗?写24个子类去实现接口,明显不合适。
这时候如果用到装饰者模式,代码则会变成:

  1 interface IEatFruit{
  2     public void eatFruit();
  3 }
  4 
  5 class PersonA implements IEatFruit{
  6     IEatFruit eat;
  7     public PersonA(){
  8         this.eat = this;
  9     }
 10     public PersonA(IEatFruit _eat){
 11         this.eat = _eat;
 12     }
 13     @Override
 14     public void eatFruit() {
 15         if(!(this.eat instanceof PersonA)){
 16             this.eat.eatFruit();
 17             System.out.println("吃苹果"); 
 18         }else{
 19             System.out.println("吃苹果"); 
 20         }
 21     }
 22     
 23 }
 24 class PersonB implements IEatFruit{
 25     IEatFruit eat;
 26     public PersonB(){
 27         this.eat = this;
 28     }
 29     public PersonB(IEatFruit _eat){
 30         this.eat = _eat;
 31     }
 32     @Override
 33     public void eatFruit() {
 34         if(!(this.eat instanceof PersonB)){
 35             this.eat.eatFruit();
 36             System.out.println("吃香蕉"); 
 37         }else{
 38             System.out.println("吃香蕉"); 
 39         }
 40     }
 41     
 42 }
 43 class PersonC implements IEatFruit{
 44     IEatFruit eat;
 45     public PersonC(){
 46         this.eat = this;
 47     }
 48     public PersonC(IEatFruit _eat){
 49         this.eat = _eat;
 50     }
 51     @Override
 52     public void eatFruit() {
 53         if(!(this.eat instanceof PersonC)){
 54             this.eat.eatFruit();
 55             System.out.println("吃鸭梨"); 
 56         }else{
 57             System.out.println("吃鸭梨"); 
 58         }
 59     }
 60     
 61 }
 62 class PersonD implements IEatFruit{
 63     IEatFruit eat;
 64     public PersonD(){
 65         this.eat = this;
 66     }
 67     public PersonD(IEatFruit _eat){
 68         this.eat = _eat;
 69     }
 70     @Override
 71     public void eatFruit() {
 72         if(!(this.eat instanceof PersonD)){
 73             this.eat.eatFruit();
 74             System.out.println("吃橘子"); 
 75         }else{
 76             System.out.println("吃橘子"); 
 77         }
 78     }
 79     
 80 }
 81 
 82 
 83 
 84 public class Demo2 {
 85 
 86     public static void main(String[] args) {
 87         //这样就可以通过上述4类人来相互装饰,就可以随意任意一种组合“吃水果”
 88         //如:吃橘子->吃苹果
 89         PersonD d = new PersonD();
 90         PersonA a = new PersonA(d);
 91         a.eatFruit();
 92         System.out.println("-------我是分割线------------");
 93         //如:吃苹果->吃橘子->吃鸭梨->吃香蕉
 94         PersonA a2 = new PersonA();
 95         PersonD d2 = new PersonD(a2);
 96         PersonC c2 = new PersonC(d2);
 97         PersonB b2 = new PersonB(c2);
 98         b2.eatFruit();
 99     }
100 
101 }

输出结果如下:
吃橘子
吃苹果
-------我是分割线------------
吃苹果
吃橘子
吃鸭梨
吃香蕉

最后总结
继承实现的增强类和修饰模式实现的增强类有何区别?
继承实现的增强类:
优点:代码结构清晰,而且实现简单.
缺点:对于每一个的需要增强的类都要创建具体的子类来帮助其增强,这样会导致
继承体系过于庞大。
装饰者模式实现的增强类:
优点:内部可以通过多态技术对多个需要增强的类进行增强, 可以使这些装饰类
达到互相装饰的效果。使用比较灵活。
缺点:需要内部通过多态维护需要被增强的类的实例。进而使得代码稍微复杂

原文地址:https://www.cnblogs.com/fnz0/p/5406402.html