• 设计模式(十四)Chain of Responsibility模式


      Chain of Responsibility模式就是当外部请求程序进行某个处理,但程序暂时无法直接决定由哪个对象负责处理时,就需要推卸责任。也就是说,当一个人被要求做什么事时,如果他可以做就自己做,如果不能做就转给下一个人,以此类推。

      下面是示例程序的类图。

      

      下面是示例程序代码。

     1 package bigjunoba.bjtu.handler;
     2 
     3 public class Trouble {
     4 
     5     private int number;
     6 
     7     public Trouble(int number) {
     8         this.number = number;
     9     }
    10 
    11     public int getNumber() {
    12         return number;
    13     }
    14     
    15     public String toString() {
    16         return "[Trouble " + number + "]"; 
    17     }
    18     
    19 }

      Trouble类是表示发生的问题的类,number作为问题编号,通过getNumber方法得到问题编号。

     1 package bigjunoba.bjtu.handler;
     2 
     3 public abstract class Support {
     4 
     5     private String name;
     6     private Support next;
     7     
     8     public Support(String name) {
     9         super();
    10         this.name = name;
    11     }
    12 
    13     public Support setNext(Support next) {
    14         this.next = next;
    15         return next;
    16     }
    17     
    18     public final void support(Trouble trouble) {
    19         if (resolve(trouble)) {
    20             done(trouble);
    21         } else if (next != null) {
    22             next.support(trouble);
    23         }else {
    24             fail(trouble);
    25         }
    26     }
    27     
    28     public String toString() {
    29         return "[" + name + "]";
    30     }
    31     
    32     protected abstract boolean resolve(Trouble trouble);
    33     
    34     protected void done(Trouble trouble) {
    35         System.out.println(trouble + " is resolved by " + this + "." );
    36     }
    37     
    38     protected void fail(Trouble trouble) {
    39         System.out.println(trouble + " cannot be resolved.");
    40     }
    41     
    42 }

      Support类是用来解决问题的抽象类,它是职责链上的对象。next字段保存了要推卸给的对象,即Support类的实例,可以通过setNext方法设定该对象。resolve方法如果返回true,则表示问题已经被处理,如果返回false,则表示问题还没有被处理。support方法调用resolve方法,如果解决了问题,那么就调用done方法,如果否则将问题交给下一个对象,如果到最后一个对象仍然没有人处理,那么就调用fail方法。这里注意的是support方法调用抽象resolve方法,这属于Template Method模式。

     1 package bigjunoba.bjtu.concretehandler;
     2 
     3 import bigjunoba.bjtu.handler.Support;
     4 import bigjunoba.bjtu.handler.Trouble;
     5 
     6 public class NoSupport extends Support{
     7 
     8     public NoSupport(String name) {
     9         super(name);
    10     }
    11 
    12     @Override
    13     protected boolean resolve(Trouble trouble) {
    14         return false;
    15     }
    16     
    17 }
     1 package bigjunoba.bjtu.concretehandler;
     2 
     3 import bigjunoba.bjtu.handler.Support;
     4 import bigjunoba.bjtu.handler.Trouble;
     5 
     6 public class OddSupport extends Support {
     7 
     8     public OddSupport(String name) {
     9         super(name);
    10     }
    11 
    12     @Override
    13     protected boolean resolve(Trouble trouble) {
    14         if (trouble.getNumber() % 2 == 1) {
    15             return true;
    16         } else {
    17             return false;
    18         }
    19     }
    20     
    21 }
    package bigjunoba.bjtu.concretehandler;
    
    import bigjunoba.bjtu.handler.Support;
    import bigjunoba.bjtu.handler.Trouble;
    
    public class SpecilaSupport extends Support{
    
        private int number;
        
        public SpecilaSupport(String name, int number) {
            super(name);
            this.number = number;
        }
    
        @Override
        protected boolean resolve(Trouble trouble) {
            if (trouble.getNumber() == number) {
                return true;
            } else {
                return false;
            }
        }
    }
     1 package bigjunoba.bjtu.concretehandler;
     2 
     3 import bigjunoba.bjtu.handler.Support;
     4 import bigjunoba.bjtu.handler.Trouble;
     5 
     6 public class LimitSupport extends Support{
     7     
     8     private int limit;
     9 
    10     public LimitSupport(String name, int limit) {
    11         super(name);
    12         this.limit = limit;
    13     }
    14 
    15     @Override
    16     protected boolean resolve(Trouble trouble) {
    17         if (trouble.getNumber() < limit) {
    18             return true;
    19         } else {
    20             return false;
    21         }
    22     }
    23     
    24 }

      这四种类Support类的子类不难理解。NoSupport类永远不解决问题;LimitSupport类只解决编号小于limit值的问题;OddSupport类只解决奇数编号问题;SpecialSupport类只解决特定编号的问题。

     1 package bigjunoba.bjtu.test;
     2 
     3 import bigjunoba.bjtu.concretehandler.LimitSupport;
     4 import bigjunoba.bjtu.concretehandler.NoSupport;
     5 import bigjunoba.bjtu.concretehandler.OddSupport;
     6 import bigjunoba.bjtu.concretehandler.SpecilaSupport;
     7 import bigjunoba.bjtu.handler.Support;
     8 import bigjunoba.bjtu.handler.Trouble;
     9 
    10 public class Main {
    11 
    12     public static void main(String[] args) {
    13         Support lian1 = new NoSupport("LianOne");
    14         Support lian2 = new LimitSupport("LianTwo", 100);
    15         Support lian3 = new SpecilaSupport("LianThree", 429);
    16         Support lian4 = new LimitSupport("LianFour", 200);
    17         Support lian5 = new OddSupport("LianFive");
    18         Support lian6 = new LimitSupport("LianSix", 300);
    19         //形成职责链
    20         lian1.setNext(lian2).setNext(lian3).setNext(lian4).setNext(lian5).setNext(lian6);
    21         //制造各种问题
    22         for (int i = 0; i < 500; i += 33) {
    23             lian1.support(new Trouble(i));
    24         }
    25     }
    26     
    27 }

      Main类首先生成了6个解决问题的实例,虽然都是Support类型的,但实际上由于Support类是抽象类,因此这些实例分别是四个不同的子类的实例。然后形成了职责链,接着制造问题进行处理。

    [Trouble 0] is resolved by [LianTwo].
    [Trouble 33] is resolved by [LianTwo].
    [Trouble 66] is resolved by [LianTwo].
    [Trouble 99] is resolved by [LianTwo].
    [Trouble 132] is resolved by [LianFour].
    [Trouble 165] is resolved by [LianFour].
    [Trouble 198] is resolved by [LianFour].
    [Trouble 231] is resolved by [LianFive].
    [Trouble 264] is resolved by [LianSix].
    [Trouble 297] is resolved by [LianFive].
    [Trouble 330] cannot be resolved.
    [Trouble 363] is resolved by [LianFive].
    [Trouble 396] cannot be resolved.
    [Trouble 429] is resolved by [LianThree].
    [Trouble 462] cannot be resolved.
    [Trouble 495] is resolved by [LianFive].
    

       根据输出结果来举一个例子具体分析一下这个过程。假设问题编号是429,那么可以这样来分析,首先创建了一个Trouble实例,并且把问题编号number设置为429,然后这个429问题实例传递给support方法,并用lian1来调用这个方法。主要分析的是调用方法的过程:先调用NoSupport类的resolve方法,结果返回false,然后next字段保存的是lian2,不为空,因此要执行lian2的support方法...以此类推,最后发现lian1,2都解决不了,最后交给了3,3可以解决,程序结束。这里的思想是用到了递归。

      有一个时序图也可以用来帮助理解。

      下面是Chain of Responsibility模式的类图。

       这里对类图不做过多解释,通过示例程序对这一模式理解应该很到位。

  • 相关阅读:
    第三十八条:检查参数的有效性
    第二十九条:优先考虑类型安全的异构容器
    第二十八条:利用有限制通配符来提升API的灵活性
    C# 利用第三方SharpZipLib进行ZIP压缩
    无法解决 equal to 操作中 "Chinese_PRC_CI_AS_WS" 和 "Chinese_PRC_CI_AS" 之间的排序规则冲突
    使用EasyUI的treegrid犯的个低级错误
    Js千位分隔符
    Google Chrom浏览器默认只能显示字体大小大于等于12px
    Asp.Net2.0开发小问题汇总
    Oracle dbms_output.put_line长度限制问题
  • 原文地址:https://www.cnblogs.com/BigJunOba/p/8709208.html
Copyright © 2020-2023  润新知