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


    定义

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

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

    特点

    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
  • 相关阅读:
    整理了8个Python中既冷门又实用的技巧
    python中68个内置函数的总结
    Python中常见的8种数据结构的实现方法(建议收藏)
    python基础教程:dir()和__dict__属性的区别
    Python 优雅获取本机 IP 方法
    Python类中的self到底是干啥的
    python中反转列表的三种方式
    Flask学习笔记(2)-login_page
    利用Flask + python3.6+MYSQL编写一个简单的评论模块。
    最近写了个自动填写调查的问卷的简单爬虫
  • 原文地址:https://www.cnblogs.com/hammerc/p/4743790.html
Copyright © 2020-2023  润新知