代码改变世界

结构类模式(四):装饰(Decorator)

2016-10-27 14:13  阿诚de窝  阅读(308)  评论(0编辑  收藏  举报

定义

动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

特点

  1. 装饰对象和真实对象有相同的接口。这样客户端对象就能以和真实对象相同的方式和装饰对象交互。
  2. 装饰对象包含一个真实对象的引用(reference)
  3. 装饰对象接受所有来自客户端的请求。它把这些请求转发给真实的对象。
  4. 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。

UML

优点

  1. Decorator模式与继承关系的目的都是要扩展对象的功能,但是Decorator可以提供比继承更多的灵活性。
  2. 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。

缺点

  1. 这种比继承更加灵活机动的特性,也同时意味着更加多的复杂性。
  2. 装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。
  3. 装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。

应用场景

  1. 需要扩展一个类的功能,或给一个类添加附加职责。
  2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
  3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
  4. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

示例

实现一个奖金计算的程序,奖金的计算是比较复杂的,普通员工有每月的业绩奖金和累计奖金,如果是经理每月还有团队奖金,而公司需要根据每月的情况来指定具体的奖金数额,所以奖金的运算系数会出现变动,同时也会添加新的奖金类型,比如和上一月业绩相比提升百分之多少之后会增加环比奖金,可可能会去掉指定的奖金类型,比如去掉了经理的团队奖金。

Java

  1 import java.util.Date;
  2 import java.util.HashMap;
  3 import java.util.Iterator;
  4 import java.util.Map;
  5 
  6 public class Main
  7 {
  8     public static void main(String[] args)
  9     {
 10         //创建需要被装饰的类
 11         Component c = new ConcreteComponent();
 12         
 13         //使用3种奖金计算的装饰类对其进行装饰
 14         Decorator d1 = new MonthPrizeDecorator(c);
 15         Decorator d2 = new SumPrizeDecorator(d1);
 16         Decorator d3 = new GroupPrizeDecorator(d2);
 17         
 18         //运算得到不同的员工应发的奖金
 19         double zs = d3.calcPrize("张三", null, null);
 20         System.out.println("张三得到的奖金是:" + zs);
 21         double ls = d3.calcPrize("李四", null, null);
 22         System.out.println("李四得到的奖金是:" + ls);
 23         double ww = d3.calcPrize("王五", null, null);
 24         System.out.println("王五得到的奖金是:" + ww);
 25     }
 26 
 27     /**
 28      * 模拟从数据库中取出的业务额度
 29      */
 30     public static class TempDB
 31     {
 32         public static Map<String, Double> mapMonthSaleMoney = new HashMap<>();
 33         
 34         static
 35         {
 36             mapMonthSaleMoney.put("张三", 15000.0);
 37             mapMonthSaleMoney.put("李四", 25000.0);
 38             mapMonthSaleMoney.put("王五", 20000.0);
 39         }
 40         
 41         public static boolean checkManager(String user)
 42         {
 43             return user.equals("王五");
 44         }
 45     }
 46     
 47     /**
 48      * 计算奖金的组件接口
 49      */
 50     public static abstract class Component
 51     {
 52         /**
 53          * 计算某人在某个时间段内的奖金
 54          */
 55         public abstract double calcPrize(String user, Date begin, Date end);
 56     }
 57 
 58     /**
 59      * 基本实现,没有奖金
 60      */
 61     public static class ConcreteComponent extends Component
 62     {
 63         @Override
 64         public double calcPrize(String user, Date begin, Date end)
 65         {
 66             return 0;
 67         }
 68     }
 69 
 70     /**
 71      * 装饰类接口,需要和被装饰类实现一样的接口
 72      */
 73     public static abstract class Decorator extends Component
 74     {
 75         /**
 76          * 持有被装饰的类的实例
 77          */
 78         protected Component c;
 79         
 80         public Decorator(Component c)
 81         {
 82             this.c = c;
 83         }
 84 
 85         @Override
 86         public double calcPrize(String user, Date begin, Date end)
 87         {
 88             return c.calcPrize(user, begin, end);
 89         }
 90     }
 91 
 92     /**
 93      * 计算当月业务奖金
 94      */
 95     public static class MonthPrizeDecorator extends Decorator
 96     {
 97         public MonthPrizeDecorator(Component c)
 98         {
 99             super(c);
100         }
101 
102         @Override
103         public double calcPrize(String user, Date begin, Date end)
104         {
105             double money = super.calcPrize(user, begin, end);
106             
107             double prize = TempDB.mapMonthSaleMoney.get(user) * 0.03;
108             System.out.println(user + "当前业务奖金是:" + prize);
109             
110             return money + prize;
111         }
112     }
113 
114     /**
115      * 计算当月累计奖金
116      */
117     public static class SumPrizeDecorator extends Decorator
118     {
119         public SumPrizeDecorator(Component c)
120         {
121             super(c);
122         }
123 
124         @Override
125         public double calcPrize(String user, Date begin, Date end)
126         {
127             double money = super.calcPrize(user, begin, end);
128 
129             double sum = 0.0;
130             Iterator<Double> i = TempDB.mapMonthSaleMoney.values().iterator();
131             while (i.hasNext())
132             {
133                 sum += i.next();
134             }
135             
136             double prize = sum * 0.001;
137             System.out.println(user + "当前累计奖金是:" + prize);
138 
139             return money + prize;
140         }
141     }
142 
143     /**
144      * 计算当前团队奖金,仅业务经理有
145      */
146     public static class GroupPrizeDecorator extends Decorator
147     {
148         public GroupPrizeDecorator(Component c)
149         {
150             super(c);
151         }
152 
153         @Override
154         public double calcPrize(String user, Date begin, Date end)
155         {
156             double money = super.calcPrize(user, begin, end);
157 
158             if(!TempDB.checkManager(user))
159             {
160                 System.out.println(user + "不是团队经理没有团队奖金");
161                 return money;
162             }
163             
164             //假设都是一个团队的
165             double sum = 0.0;
166             Iterator<Double> i = TempDB.mapMonthSaleMoney.values().iterator();
167             while (i.hasNext())
168             {
169                 sum += i.next();
170             }
171 
172             double prize = sum * 0.0015;
173             System.out.println(user + "获得的团队奖金是:" + prize);
174 
175             return money + prize;
176         }
177     }
178 }
View Code