参考文献

责任链模式

  • 允许你将请求沿着处理者链进行发送. 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者.

组件

  • Request: 责任链中的请求对象

    1
    public class Request{}
  • Handler: 定义处理请求的接口

    1
    2
    3
    4
    public interface Handler{
    boolean shouldSkip(Request request);
    boolean handle(Request request);
    }
  • RequestHandler: 实际处理请求的类

    • 如果它可以处理请求,则进行处理,否则将会发送给其后继者
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public RequestHandler implement Handler{
    @Override
    boolean shouldSkip(Request request){
    // 判断当前请求是否可以被处理
    return true;
    }
    @Override
    boolean handle(Request request){
    if(shouldSkip(request)){
    return false;
    }
    // doHandle
    return true;
    }
    }
  • Client: 将命令发送到链中可以处理该命令的第一个对象

使用场景

  • 多个对象可以处理一个命令:当一个请求需要经过多个处理程序进行处理时,每个处理程序都有可能处理该请求,并且可以按照一定的顺序依次传递处理.
  • 处理程序事先未知:发送请求的客户端不需要知道请求应该由哪个具体的处理程序来处理,它只需要将请求发送给责任链的第一个处理程序,由处理程序自动确定后续的处理者.
  • 处理程序应自动确定:处理程序的选择和顺序应该在运行时动态确定,而不是在编译时静态确定.
  • 希望请求发送到一组对象而不明确指定其接收者:请求的发送者不需要明确指定接收者,而是将请求发送给整个责任链,由责任链中的处理程序自行决定是否处理请求以及谁来处理.
  • 必须以动态方式指定可以处理命令的对象组:责任链允许在运行时动态添加、删除或修改处理程序,以满足特定的需求,从而更灵活地配置处理程序的组成.

实际场景示例

  • 请求处理管道:例如,在Web开发中,可以使用责任链模式来构建一个请求处理管道.每个处理程序代表一个环节,可以在请求经过管道时进行各种处理,如身份验证、授权、记录日志等.
  • 日志记录器:在一个应用程序中,可以有多个日志记录器,分别负责记录不同级别的日志信息.使用责任链模式可以构建一个日志记录器链,当有日志信息到达时,会根据日志级别选择适当的记录器进行处理.
  • 异常处理:在一个系统中,可以有多个异常处理程序,每个处理程序负责处理特定类型的异常.使用责任链模式可以构建一个异常处理链,当某个异常被抛出时,会依次由处理程序进行处理,直到找到能够处理该异常的处理程序为止.
  • 购物车优惠券:在电子商务系统中,购物车可能会有多个优惠券可供用户选择.使用责任链模式可以构建一个优惠券处理链,当用户提交订单时,会依次检查并应用符合条件的优惠券,直到找到适用的优惠券或者没有更多的处理程序为止.
  • 审批流程:在企业中,有许多审批流程需要经过多个级别的审批人.使用责任链模式可以构建一个审批处理链,每个处理程序代表一个审批人,根据审批规则依次进行审批,直到达到最终的决策.
  • 身份验证和权限检查:在身份验证和权限检查系统中,可以使用责任链模式来验证用户的身份和权限。每个处理者可以检查特定的条件,例如用户名和密码的正确性、账户是否锁定等。如果一个处理者无法通过验证,可以将请求传递给下一个处理者。
  • 数据过滤和转换:在数据处理过程中,可以使用责任链模式来进行数据过滤和转换。每个处理者可以根据特定的条件过滤数据或对数据进行转换,然后将处理后的数据传递给下一个处理者。

使用方法

  • 推荐使用Apache Commons Chain实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package design.pattern.behavioral.chainofresponsibility.commonchain;


import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;

/**
* @author HoleLin
*/
public class ParseProcess implements Command {

@Override
public boolean execute(Context context) throws Exception {
Test.Info info = (Test.Info) context.get("KEY");
System.out.println("Parse result:" + info.getName());
return false;
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package design.pattern.behavioral.chainofresponsibility.commonchain;


import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;

/**
* @author HoleLin
*/
public class ComputeProcess implements Command {

@Override
public boolean execute(Context context) throws Exception {
Test.Info info = (Test.Info) context.get("KEY");
System.out.println("result:" + (info.getA() + info.getB()));
return false;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
package design.pattern.behavioral.chainofresponsibility.commonchain;

import org.apache.commons.chain.impl.ChainBase;

/**
* @author HoleLin
*/
public class ProcessChain extends ChainBase {


}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package design.pattern.behavioral.chainofresponsibility.commonchain;

import org.apache.commons.chain.Command;
import org.apache.commons.chain.impl.ContextBase;

/**
* @author HoleLin
*/
public class Test {


static class Info {
private final String name;
private final Integer a;
private final Integer b;

public Info(String name, Integer a, Integer b) {
this.name = name;
this.a = a;
this.b = b;
}

public String getName() {
return name;
}

public Integer getA() {
return a;
}

public Integer getB() {
return b;
}
}

public static void main(String[] args) {
ParseProcess parseProcess = new ParseProcess();
ComputeProcess computeProcess = new ComputeProcess();
ProcessChain processChain = new ProcessChain();
register(processChain, parseProcess);
register(processChain, computeProcess);

ContextBase context = new ContextBase();
Info info = new Info("cs", 1, 2);
context.put("KEY", info);
try {
processChain.execute(context);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

private static void register(ProcessChain processChain, Command command) {
processChain.addCommand(command);
}
}

// output
Parse result:cs
result:3