设计模式(十四)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模式的类图。

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

原文地址:https://www.cnblogs.com/BigJunOba/p/8709208.html