设计模式-责任链模式

模式定义

责任链模式(Chain of Responsibility) 是行为型设计模式之一,其将链中每一个节点看作是一个对象,每个节点处理的请求均不同,从而避免了请求的发送者和接收者之间的耦合关系,且内部自动维护一个下一节点对象。当一个请求从链式的首端发出时,会沿着链的路径依次传递给每一个节点对象,直至有对象处理这个请求为止。

主要作用

责任链模式 解耦了请求与处理,客户只需将请求发送到链上即可,无需关心请求的具体内容和处理细节,请求会自动进行传递直至有节点对象进行处理。

UML类图

责任链模式

角色

  • Handler(抽象处理者):它定义了一个处理请求的接口,一般设计为抽象类,由于不同的具体处理者处理请求的方式不同,因此在其中定义了抽象请求处理方法。因为每一个处理者的下家还是一个处理者,因此在抽象处理者中定义了一个抽象处理者类型的对象,作为其对下家的引用。通过该引用,处理者可以连成一条链。

  • ConcreteHandler(具体处理者):它是抽象处理者的子类,可以处理用户请求,在具体处理者类中实现了抽象处理者中定义的抽象请求处理方法,在处理请求之前需要进行判断,看是否有相应的处理权限,如果可以处理请求就处理它,否则将请求转发给后继者;在具体处理者中可以访问链中下一个对象,以便请求的转发。

模式优点

  1. 对象仅需知道该请求会被处理即可,且链中的对象不需要知道链的结构,由客户端负责链的创建,降低了系统的耦合度。

  2. 请求处理对象仅需维持一个指向其后继者的引用,而不需要维持它对所有的候选处理者的引用,可简化对象的相互连接。

  3. 链路结构灵活,可以通过改变链路结构动态地新增或删减责任。

  4. 新增一个新的具体请求处理者时无须修改原有代码,只需要在客户端重新建链即可,符合 “开闭原则”。

模式缺点

  1. 一个请求可能因职责链没有被正确配置而得不到处理。

  2. 对于比较长的职责链,请求的处理可能涉及到多个处理对象,系统性能将受到一定影响,且不方便调试。

  3. 如果节点对象存在循环引用时,会造成死循环,导致系统崩溃。

适用场景

  • 有多个对象可以处理同一个请求,具体哪个对象处理该请求待运行时刻再确定,客户端只需将请求提交到链上,而无须关心请求的处理对象是谁以及它是如何处理的。

  • 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。

  • 可动态指定一组对象处理请求,客户端可以动态创建职责链来处理请求,还可以改变链中处理者之间的先后次序。

使用步骤

定义抽象处理者

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
package main.java.com.study.designPatterns.chain.common;

/**
* @author: whb
* @description: 定义抽象处理者--职责的接口,也就是处理请求的接口
*/
public abstract class Handler {
/**
* 持有后继的职责对象
*/
protected Handler successor;

/**
* 设置后继的职责对象
*
* @param successor 后继的职责对象
*/
public void setSuccessor(Handler successor) {
this.successor = successor;
}

/**
* 示意处理请求的方法,虽然这个示意方法是没有传入参数,
* 但实际是可以传入参数的,根据具体需要来选择是否传递参数
*/
public abstract void handleRequest();
}

定义具体处理者

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
package main.java.com.study.designPatterns.chain.common;

/**
* @author: whb
* @description: 定义具体处理者--具体的职责对象,用来处理请求
*/
public class ConcreteHandler1 extends Handler {
@Override
public void handleRequest() {
//根据某些条件来判断是否属于自己处理的职责范围
//判断条件比如:从外部传入的参数,或者这里主动去获取的外部数据,
//如从数据库中获取等,下面这句话只是个示意
boolean someCondition = false;

if (someCondition) {
//如果属于自己处理的职责范围,就在这里处理请求
//具体的处理代码
System.out.println("具体处理者1 处理请求...");
} else {
//如果不属于自己处理的职责范围,那就判断是否还有后继的职责对象
//如果有,就转发请求给后继的职责对象
//如果没有,什么都不做,自然结束
if (this.successor != null) {
this.successor.handleRequest();
}
}
}
}

package main.java.com.study.designPatterns.chain.common;

/**
* @author: whb
* @description: 具体处理者2
*/
public class ConcreteHandler2 extends Handler {
@Override
public void handleRequest() {
//根据某些条件来判断是否属于自己处理的职责范围
//判断条件比如:从外部传入的参数,或者这里主动去获取的外部数据,
//如从数据库中获取等,下面这句话只是个示意
boolean someCondition = true;

if (someCondition) {
//如果属于自己处理的职责范围,就在这里处理请求
//具体的处理代码
System.out.println("具体处理者2 处理请求...");
} else {
//如果不属于自己处理的职责范围,那就判断是否还有后继的职责对象
//如果有,就转发请求给后继的职责对象
//如果没有,什么都不做,自然结束
if (this.successor != null) {
this.successor.handleRequest();
}
}
}
}

客户端调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main.java.com.study.designPatterns.chain.common;

/**
* @author: whb
* @description: 客户端调用
*/
public class Client {
public static void main(String[] args) {
//先要组装职责链
Handler h1 = new ConcreteHandler1();
Handler h2 = new ConcreteHandler2();

h1.setSuccessor(h2);
//然后提交请求
h1.handleRequest();
}
}

模式示例

背景

很多公司都有这样的福利,就是项目组或者是部门可以向公司申请一些聚餐费用,用于组织项目组成员或者是部门成员进行聚餐活动,以增进人员之间的情感,更有利于工作中的相互合作。

申请聚餐费用的大致流程一般是:由申请人先填写申请单,然后交给领导审查,如果申请批准下来了,领导会通知申请人审批通过,然后申请人去财务核领费用,如果没有核准,领导会通知申请人审批未通过,此事也就此作罢了。

不同级别的领导,对于审批的额度是不一样的,比如:项目经理只能审批500元以内的申请;部门经理能审批1000元以内的申请;而总经理可以审核任意额度的申请。

也就是说,当某人提出聚餐费用申请的请求后,该请求会由项目经理、部门经理、总经理之中的某一位领导来进行相应的处理,但是提出申请的人并不知道最终会由谁来处理他的请求,一般申请人是把自己的申请提交给项目经理,或许最后是由总经理来处理他的请求,但是申请人并不知道应该由总经理来处理他的申请请求。

分析

当某人提出聚餐费用申请的请求后,该请求会在项目经理-部门经理-总经理这样一条领导处理链上进行传递,发出请求的人并不知道谁会来处理他的请求,每个领导会根据自己的职责范围,来判断是处理请求还是把请求交给更高级的领导,只要有领导处理了,传递就结束了。

需要把每位领导的处理独立出来,实现成单独的职责处理对象,然后为它们提供一个公共的、抽象的父职责对象,这样就可以在客户端来动态的组合职责链,实现不同的功能要求了。

具体代码

定义抽象处理者

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
package main.java.com.study.designPatterns.chain.demoTwo;

/**
* @author: whb
* @description: 抽象处理者类,定义职责对象
*/
public abstract class Handler {
/**
* 持有下一个处理请求的对象
*/
protected Handler successor = null;

/**
* 设置下一个处理请求的对象
*
* @param successor 下一个处理请求的对象
*/
public void setSuccessor(Handler successor) {
this.successor = successor;
}

/**
* 处理聚餐费用的申请
*
* @param user 申请人
* @param fee 申请的钱数
* @return 成功或失败的具体通知
*/
public abstract String handleFeeRequest(String user, double fee);
}

定义具体处理者

项目经理:

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
package main.java.com.study.designPatterns.chain.demoTwo;

/**
* @author: whb
* @description: 具体处理者--项目经理
*/
public class ProjectManager extends Handler {
@Override
public String handleFeeRequest(String user, double fee) {
String str = "";
//项目经理的权限比较小,只能在500以内
if (fee < 500) {
//为了测试,简单点,只同意小李的
if ("小李".equals(user)) {
str = "项目经理同意" + user + "聚餐费用" + fee + "元的请求";
} else {
//其它人一律不同意
str = "项目经理不同意" + user + "聚餐费用" + fee + "元的请求";
}
return str;
} else {
//超过500,继续传递给级别更高的人处理
if (this.successor != null) {
return successor.handleFeeRequest(user, fee);
}
}
return str;
}
}

部门经理:

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
package main.java.com.study.designPatterns.chain.demoTwo;

/**
* @author: whb
* @description: 具体处理者--部门经理
*/
public class DepManager extends Handler {
@Override
public String handleFeeRequest(String user, double fee) {
String str = "";
//部门经理的权限只能在1000以内
if (fee < 1000) {
//为了测试,简单点,只同意小李申请的
if ("小李".equals(user)) {
str = "部门经理同意" + user + "聚餐费用" + fee + "元的请求";
} else {
//其它人一律不同意
str = "部门经理不同意" + user + "聚餐费用" + fee + "元的请求";
}
return str;
} else {
//超过1000,继续传递给级别更高的人处理
if (this.successor != null) {
return this.successor.handleFeeRequest(user, fee);
}
}
return str;
}
}

总经理:

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
package main.java.com.study.designPatterns.chain.demoTwo;

/**
* @author: whb
* @description: 具体处理者--总经理
*/
public class GeneralManager extends Handler {
@Override
public String handleFeeRequest(String user, double fee) {
String str = "";
//总经理的权限很大,只要请求到了这里,他都可以处理
if (fee >= 1000) {
//为了测试,简单点,只同意小李的
if ("小李".equals(user)) {
str = "总经理同意" + user + "聚餐费用" + fee + "元的请求";
} else {
//其它人一律不同意
str = "总经理不同意" + user + "聚餐费用" + fee + "元的请求";
}
return str;
} else {
//如果还有后继的处理对象,继续传递
if (this.successor != null) {
return successor.handleFeeRequest(user, fee);
}
}
return str;
}
}

客户端调用

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
package main.java.com.study.designPatterns.chain.demoTwo;

/**
* @author: whb
* @description: 测试类
*/
public class Client {
public static void main(String[] args) {
//先要组装职责链
Handler h1 = new GeneralManager();
Handler h2 = new DepManager();
Handler h3 = new ProjectManager();
h3.setSuccessor(h2);
h2.setSuccessor(h1);

//开始测试
String ret1 = h3.handleFeeRequest("小李", 300);
System.out.println("the ret1=" + ret1);
String ret2 = h3.handleFeeRequest("小张", 300);
System.out.println("the ret2=" + ret2);

String ret3 = h3.handleFeeRequest("小李", 600);
System.out.println("the ret3=" + ret3);
String ret4 = h3.handleFeeRequest("小张", 600);
System.out.println("the ret4=" + ret4);

String ret5 = h3.handleFeeRequest("小李", 1200);
System.out.println("the ret5=" + ret5);
String ret6 = h3.handleFeeRequest("小张", 1200);
System.out.println("the ret6=" + ret6);
}
}

拓展-处理多种请求

上面的示例是同一个职责链处理一种请求的情况,现在有这样的需求,还是费用申请的功能,这次是申请预支差旅费,假设还是同一流程,也就是组合同一个职责链,从项目经理-传递给部门经理-传递给总经理,虽然流程相同,但是每个处理类需要处理两种请求,它们的具体业务逻辑是不一样的。

简单的处理方式

简单处理方式就是为每种业务单独定义一个方法,然后客户端根据不同的需要调用不同的方法。
直接改造上面的代码,这里故意把两个方法做的有些不一样,一个是返回String类型的值,一个是返回boolean类型的值;一个返回到客户端再输出信息,一个是直接在职责处理里面就输出信息。

  1. 首先是改造职责对象的接口,添加上新的业务方法:
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
package main.java.com.study.designPatterns.chain.demoTwo;

/**
* @author: whb
* @description: 抽象处理者类,定义职责对象
*/
public abstract class Handler {
/**
* 持有下一个处理请求的对象
*/
protected Handler successor = null;

/**
* 设置下一个处理请求的对象
*
* @param successor 下一个处理请求的对象
*/
public void setSuccessor(Handler successor) {
this.successor = successor;
}

/**
* 处理聚餐费用的申请
*
* @param user 申请人
* @param fee 申请的钱数
* @return 成功或失败的具体通知
*/
public abstract String handleFeeRequest(String user, double fee);

/**
* 处理预支差旅费用的申请
*
* @param user 申请人
* @param requestFee 申请的钱数
* @return 是否同意
*/
public abstract boolean handlePreFeeRequest(String user, double requestFee);
}
  1. 职责的接口发生了改变,对应的处理类也要改变,这几个处理类是类似的,原有的功能不变,然后在新的实现方法里面,同样判断一下是否属于自己处理的范围,如果属于自己处理的范围那就处理,否则就传递到下一个处理。

项目经理:

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
package main.java.com.study.designPatterns.chain.demoTwo;

/**
* @author: whb
* @description: 具体处理者--项目经理
*/
public class ProjectManager extends Handler {
@Override
public String handleFeeRequest(String user, double fee) {
String str = "";
//项目经理的权限比较小,只能在500以内
if (fee < 500) {
//为了测试,简单点,只同意小李的
if ("小李".equals(user)) {
str = "项目经理同意" + user + "聚餐费用" + fee + "元的请求";
} else {
//其它人一律不同意
str = "项目经理不同意" + user + "聚餐费用" + fee + "元的请求";
}
return str;
} else {
//超过500,继续传递给级别更高的人处理
if (this.successor != null) {
return successor.handleFeeRequest(user, fee);
}
}
return str;
}

@Override
public boolean handlePreFeeRequest(String user, double requestNum) {
//项目经理的权限比较小,只能在5000以内
if (requestNum < 5000) {
//工作需要嘛,统统同意
System.out.println("项目经理同意" + user + "预支差旅费用" + requestNum + "元的请求");
return true;
} else {
//超过5000,继续传递给级别更高的人处理
if (this.successor != null) {
return this.successor.handlePreFeeRequest(user, requestNum);
}
}
return false;
}
}

部门经理:

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
package main.java.com.study.designPatterns.chain.demoTwo;

/**
* @author: whb
* @description: 具体处理者--部门经理
*/
public class DepManager extends Handler {
@Override
public String handleFeeRequest(String user, double fee) {
String str = "";
//部门经理的权限只能在1000以内
if (fee < 1000) {
//为了测试,简单点,只同意小李申请的
if ("小李".equals(user)) {
str = "部门经理同意" + user + "聚餐费用" + fee + "元的请求";
} else {
//其它人一律不同意
str = "部门经理不同意" + user + "聚餐费用" + fee + "元的请求";
}
return str;
} else {
//超过1000,继续传递给级别更高的人处理
if (this.successor != null) {
return this.successor.handleFeeRequest(user, fee);
}
}
return str;
}

@Override
public boolean handlePreFeeRequest(String user, double requestFee) {
//部门经理的权限20000以内
if (requestFee < 20000) {
//工作需要嘛,统统同意
System.out.println("部门经理同意" + user + "预支差旅费用" + requestFee + "元的请求");
return true;
} else {
//超过20000,继续传递给级别更高的人处理
if (this.successor != null) {
return this.successor.handlePreFeeRequest(user, requestFee);
}
}
return false;
}
}

总经理:

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
package main.java.com.study.designPatterns.chain.demoTwo;

/**
* @author: whb
* @description: 具体处理者--总经理
*/
public class GeneralManager extends Handler {
@Override
public String handleFeeRequest(String user, double fee) {
String str = "";
//总经理的权限很大,只要请求到了这里,他都可以处理
if (fee >= 1000) {
//为了测试,简单点,只同意小李的
if ("小李".equals(user)) {
str = "总经理同意" + user + "聚餐费用" + fee + "元的请求";
} else {
//其它人一律不同意
str = "总经理不同意" + user + "聚餐费用" + fee + "元的请求";
}
return str;
} else {
//如果还有后继的处理对象,继续传递
if (this.successor != null) {
return successor.handleFeeRequest(user, fee);
}
}
return str;
}

@Override
public boolean handlePreFeeRequest(String user, double requestFee) {
//总经理的权限50000以内
if (requestFee < 50000) {
//工作需要嘛,统统同意
System.out.println("总经理同意" + user + "预支差旅费用" + requestFee + "元的请求");
return true;
} else {
//如果还有后继的处理对象,继续传递
if (this.successor != null) {
return this.successor.handlePreFeeRequest(user, requestFee);
}
}
return false;
}
}
  1. 客户端调用
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
package main.java.com.study.designPatterns.chain.demoTwo;

/**
* @author: whb
* @description: 测试类
*/
public class Client {
public static void main(String[] args) {
//先要组装职责链
Handler h1 = new GeneralManager();
Handler h2 = new DepManager();
Handler h3 = new ProjectManager();
h3.setSuccessor(h2);
h2.setSuccessor(h1);

//开始测试申请聚餐费用
String ret1 = h3.handleFeeRequest("小李", 300);
System.out.println("the ret1=" + ret1);
String ret2 = h3.handleFeeRequest("小张", 300);
System.out.println("the ret2=" + ret2);

String ret3 = h3.handleFeeRequest("小李", 600);
System.out.println("the ret3=" + ret3);
String ret4 = h3.handleFeeRequest("小张", 600);
System.out.println("the ret4=" + ret4);

String ret5 = h3.handleFeeRequest("小李", 1200);
System.out.println("the ret5=" + ret5);
String ret6 = h3.handleFeeRequest("小张", 1200);
System.out.println("the ret6=" + ret6);

//开始测试申请差旅费用
h3.handlePreFeeRequest("小张", 3000);
h3.handlePreFeeRequest("小张", 6000);
h3.handlePreFeeRequest("小张", 32000);
}
}

通用请求处理方式

简单处理方式实现起来很容易,但是有一个明显的问题就是只要增加一个业务,就需要修改职责的接口,这是很不灵活的,Java开发中很强调面向接口编程,因此接口应该相对保持稳定,接口一改,需要修改的地方就太多了,频繁修改接口绝对不是个好主意。所以改造如下:

首先定义一套通用的调用框架,用一个通用的请求对象来封装请求传递的参数;
然后定义一个通用的调用方法,这个方法不去区分具体业务,所有的业务都是这一个方法,在通用的请求对象里面会有一个业务的标记进行业务区分;
到了职责对象里面,愿意处理就跟原来一样的处理方式,如果不愿意处理,就传递到下一个处理对象就好了。
对于返回值也可以来个通用的,最简单的就是使用Object类型。

具体代码

  1. 通用的请求对象的定义
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
package main.java.com.study.designPatterns.chain.demoTwo.upgrade;

/**
* @author: whb
* @description: 通用的请求对象
*/
public class RequestModel {
/**
* 表示具体的业务类型
*/
private String type;

/**
* 通过构造方法把具体的业务类型传递进来
*
* @param type 具体的业务类型
*/
public RequestModel(String type) {
this.type = type;
}

public String getType() {
return type;
}
}
  1. 此时的通用职责处理对象,在这里要实现一个通用的调用框架
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
package main.java.com.study.designPatterns.chain.demoTwo.upgrade;

/**
* @author: whb
* @description: 通用职责处理对象,在这里要实现一个通用的调用框架
*/
public abstract class Handler {
/**
* 持有下一个处理请求的对象
*/
protected Handler successor = null;

/**
* 设置下一个处理请求的对象
*
* @param successor 下一个处理请求的对象
*/
public void setSuccessor(Handler successor) {
this.successor = successor;
}

/**
* 通用的请求处理方法
*
* @param rm 通用的请求对象
* @return 处理后需要返回的对象
*/
public Object handleRequest(RequestModel rm) {
if (successor != null) {
//这个是默认的实现,如果子类不愿意处理这个请求,
//那就传递到下一个职责对象去处理
return this.successor.handleRequest(rm);
} else {
System.out.println("没有后续处理或者暂时不支持这样的功能处理");
return false;
}
}
}
  1. 现在来加上第一个业务,就是“聚餐费用申请”的处理,为了描述具体的业务数据,需要扩展通用的请求对象,把业务数据封装进去,另外定义一个请求对象
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
package main.java.com.study.designPatterns.chain.demoTwo.upgrade;

/**
* @author: whb
* @description: 具体的业务请求对象--聚餐费用申请
*/
public class FeeRequestModel extends RequestModel {
/**
* 约定具体的业务类型
*/
public final static String FEE_TYPE = "fee";

public FeeRequestModel() {
super(FEE_TYPE);
}

/**
* 申请人
*/
private String user;
/**
* 申请金额
*/
private double fee;

public String getUser() {
return user;
}

public void setUser(String user) {
this.user = user;
}

public double getFee() {
return fee;
}

public void setFee(double fee) {
this.fee = fee;
}
}
  1. 接下来该实现职责对象的处理了,首先要覆盖父类的通用业务处理方法,然后在里面处理自己想要实现的业务,不想处理的就让父类去处理,父类会默认的传递给下一个处理对象。

项目经理:

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
package main.java.com.study.designPatterns.chain.demoTwo.upgrade;

/**
* @author: whb
* @description: 具体的职责对象--项目经理
*/
public class ProjectManager extends Handler {
@Override
public Object handleRequest(RequestModel rm) {
if (FeeRequestModel.FEE_TYPE.equals(rm.getType())) {
//表示聚餐费用申请
return handleFeeRequest(rm);
} else {
//其它的项目经理暂时不想处理
return super.handleRequest(rm);
}
}

/**
* 聚餐费用处理
*
* @param rm
* @return
*/
private Object handleFeeRequest(RequestModel rm) {
//先把通用的对象造型回来
FeeRequestModel frm = (FeeRequestModel) rm;
String str = "";
//项目经理的权限比较小,只能在500以内
if (frm.getFee() < 500) {
//为了测试,简单点,只同意小李的
if ("小李".equals(frm.getUser())) {
str = "项目经理同意" + frm.getUser() + "聚餐费用" + frm.getFee() + "元的请求";
} else {
//其它人一律不同意
str = "项目经理不同意" + frm.getUser() + "聚餐费用" + frm.getFee() + "元的请求";
}
return str;
} else {
//超过500,继续传递给级别更高的人处理
if (this.successor != null) {
return successor.handleRequest(rm);
}
}
return str;
}
}

部门经理:

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
package main.java.com.study.designPatterns.chain.demoTwo.upgrade;

/**
* @author: whb
* @description: 部门经理
*/
public class DeptManager extends Handler {
@Override
public Object handleRequest(RequestModel rm) {
if (FeeRequestModel.FEE_TYPE.equals(rm.getType())) {
//表示聚餐费用申请
return handleFeeRequest(rm);
} else {
//其它的部门经理暂时不想处理
return super.handleRequest(rm);
}
}

/**
* 聚餐费用处理
*
* @param rm
* @return
*/
private Object handleFeeRequest(RequestModel rm) {
//先把通用的对象造型回来
FeeRequestModel frm = (FeeRequestModel) rm;
String str = "";
//部门经理的权限只能在1000以内
if (frm.getFee() < 1000) {
//为了测试,简单点,只同意小李的
if ("小李".equals(frm.getUser())) {
str = "部门经理同意" + frm.getUser() + "聚餐费用" + frm.getFee() + "元的请求";
} else {
//其它人一律不同意
str = "部门经理不同意" + frm.getUser() + "聚餐费用" + frm.getFee() + "元的请求";
}
return str;
} else {
//超过1000,继续传递给级别更高的人处理
if (this.successor != null) {
return successor.handleRequest(rm);
}
}
return str;
}
}

总经理:

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
package main.java.com.study.designPatterns.chain.demoTwo.upgrade;

/**
* @author: whb
* @description: 总经理
*/
public class GeneralManager extends Handler {
@Override
public Object handleRequest(RequestModel rm) {
if (FeeRequestModel.FEE_TYPE.equals(rm.getType())) {
//表示聚餐费用申请
return handleFeeRequest(rm);
} else {
//其它的总经理暂时不想处理
return super.handleRequest(rm);
}
}

/**
* 聚餐费用处理
*
* @param rm
* @return
*/
private Object handleFeeRequest(RequestModel rm) {
//先把通用的对象造型回来
FeeRequestModel frm = (FeeRequestModel) rm;
String str = "";
//总经理的权限很大,只要请求到了这里,他都可以处理
if (frm.getFee() >= 1000) {
//为了测试,简单点,只同意小李的
if ("小李".equals(frm.getUser())) {
str = "总经理同意" + frm.getUser() + "聚餐费用" + frm.getFee() + "元的请求";
} else {
//其它人一律不同意
str = "总经理不同意" + frm.getUser() + "聚餐费用" + frm.getFee() + "元的请求";
}
return str;
} else {
//如果还有后继的处理对象,继续传递
if (this.successor != null) {
return successor.handleRequest(rm);
}
}
return str;
}
}
  1. 对于客户端,唯一的麻烦是需要知道每个业务对应的具体的请求对象,因为要封装业务数据进去.
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
package main.java.com.study.designPatterns.chain.demoTwo.upgrade;

/**
* @author: whb
* @description: 客户端调用
*/
public class Client {
public static void main(String[] args) {
//先要组装职责链
Handler h1 = new GeneralManager();
Handler h2 = new DeptManager();
Handler h3 = new ProjectManager();
h3.setSuccessor(h2);
h2.setSuccessor(h1);

//开始测试申请聚餐费用
FeeRequestModel frm = new FeeRequestModel();
frm.setFee(300);
frm.setUser("小李");
//调用处理
String ret1 = (String) h3.handleRequest(frm);
System.out.println("ret1=" + ret1);

//重新设置申请金额,再调用处理
frm.setFee(800);
h3.handleRequest(frm);
String ret2 = (String) h3.handleRequest(frm);
System.out.println("ret2=" + ret2);

//重新设置申请金额,再调用处理
frm.setFee(1600);
h3.handleRequest(frm);
String ret3 = (String) h3.handleRequest(frm);
System.out.println("ret3=" + ret3);
}
}
  1. 接下来看看如何在不改动现有的框架的前提下,扩展新的业务,这样才能说明这种设计的灵活性。

假如就是要实现上面示例过的另外一个功能“预支差旅费申请”。要想扩展新的业务,第一步就是新建一个封装业务数据的对象

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
package main.java.com.study.designPatterns.chain.demoTwo.upgrade;

/**
* @author: whb
* @description: 预支差旅费用请求对象
*/
public class PreFeeRequestModel extends RequestModel {
/**
* 约定具体的业务类型
*/
public final static String FEE_TYPE = "preFee";

public PreFeeRequestModel() {
super(FEE_TYPE);
}

/**
* 申请人
*/
private String user;
/**
* 申请金额
*/
private double fee;

public String getUser() {
return user;
}

public void setUser(String user) {
this.user = user;
}

public double getFee() {
return fee;
}

public void setFee(double fee) {
this.fee = fee;
}
}
  1. 对于具体进行职责处理的类,比较好的方式就是扩展出子类来,然后在子类里面实现新加入的业务,当然也可以直接在原来的对象上改。这里采用扩展出子类的方式。
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
package main.java.com.study.designPatterns.chain.demoTwo.upgrade;

/**
* @author: whb
* @description: 实现为项目经理增加预支差旅费用申请处理的功能的子对象,
* 现在的项目经理既可以处理聚餐费用申请,又可以处理预支差旅费用申请
*/
public class ProjectManager2 extends ProjectManager {
@Override
public Object handleRequest(RequestModel rm) {
if (PreFeeRequestModel.FEE_TYPE.equals(rm.getType())) {
//表示预支差旅费用申请
return handlePreFeeRequest(rm);
} else {
//其它的让父类去处理
return super.handleRequest(rm);
}
}

/**
* 预支差旅费用
*
* @param rm
* @return
*/
private Object handlePreFeeRequest(RequestModel rm) {
//先把通用的对象造型回来
PreFeeRequestModel frm = (PreFeeRequestModel) rm;
//项目经理的权限比较小,只能在5000以内
if (frm.getFee() < 5000) {
//工作需要嘛,统统同意
System.out.println("项目经理同意" + frm.getUser() + "预支差旅费用" + frm.getFee() + "元的请求");
return true;
} else {
//超过5000,继续传递给级别更高的人处理
if (this.successor != null) {
return this.successor.handleRequest(rm);
}
}
return false;
}
}
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
package main.java.com.study.designPatterns.chain.demoTwo.upgrade;

/**
* @author: whb
* @description: 实现为部门经理增加预支差旅费用申请处理的功能的子对象,
* 现在的部门经理既可以处理聚餐费用申请,又可以处理预支差旅费用申请
*/
public class DeptManager2 extends ProjectManager {
@Override
public Object handleRequest(RequestModel rm) {
if (PreFeeRequestModel.FEE_TYPE.equals(rm.getType())) {
//表示预支差旅费用申请
return handlePreFeeRequest(rm);
} else {
//其它的让父类去处理
return super.handleRequest(rm);
}
}

/**
* 预支差旅费用
*
* @param rm
* @return
*/
private Object handlePreFeeRequest(RequestModel rm) {
//先把通用的对象造型回来
PreFeeRequestModel frm = (PreFeeRequestModel) rm;
//部门经理的权限在20000以内
if (frm.getFee() < 20000) {
//工作需要嘛,统统同意
System.out.println("部门经理同意" + frm.getUser() + "预支差旅费用" + frm.getFee() + "元的请求");
return true;
} else {
//超过20000,继续传递给级别更高的人处理
if (this.successor != null) {
return this.successor.handleRequest(rm);
}
}
return false;
}
}
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
package main.java.com.study.designPatterns.chain.demoTwo.upgrade;

/**
* @author: whb
* @description: 实现为总经理增加预支差旅费用申请处理的功能的子对象,
* 现在的总经理既可以处理聚餐费用申请,又可以处理预支差旅费用申请
*/
public class GeneralManager2 extends ProjectManager {
@Override
public Object handleRequest(RequestModel rm) {
if (PreFeeRequestModel.FEE_TYPE.equals(rm.getType())) {
//表示预支差旅费用申请
return handlePreFeeRequest(rm);
} else {
//其它的让父类去处理
return super.handleRequest(rm);
}
}

/**
* 预支差旅费用
*
* @param rm
* @return
*/
private Object handlePreFeeRequest(RequestModel rm) {
//先把通用的对象造型回来
PreFeeRequestModel frm = (PreFeeRequestModel) rm;
//总经理的权限在20000以内
if (frm.getFee() >= 20000) {
//工作需要嘛,统统同意
System.out.println("总经理同意" + frm.getUser() + "预支差旅费用" + frm.getFee() + "元的请求");
return true;
} else {
//如果还有后续,继续传递给级别更高的人处理
if (this.successor != null) {
return this.successor.handleRequest(rm);
}
}
return false;
}
}
  1. 此时的测试类
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
package main.java.com.study.designPatterns.chain.demoTwo.upgrade;

/**
* @author: whb
* @description: 拓展后的测试类
*/
public class Client2 {
public static void main(String[] args) {
//先要组装职责链
Handler h1 = new GeneralManager2();
Handler h2 = new DeptManager2();
Handler h3 = new ProjectManager2();
h3.setSuccessor(h2);
h2.setSuccessor(h1);

//开始测试申请聚餐费用
FeeRequestModel frm = new FeeRequestModel();
frm.setFee(300);
frm.setUser("小李");
//调用处理
String ret1 = (String) h3.handleRequest(frm);
System.out.println("ret1=" + ret1);

//重新设置申请金额,再调用处理
frm.setFee(800);
h3.handleRequest(frm);
String ret2 = (String) h3.handleRequest(frm);
System.out.println("ret2=" + ret2);

//重新设置申请金额,再调用处理
frm.setFee(1600);
h3.handleRequest(frm);
String ret3 = (String) h3.handleRequest(frm);
System.out.println("ret3=" + ret3);

//开始测试申请预支差旅费用
PreFeeRequestModel pfrm = new PreFeeRequestModel();
pfrm.setFee(3000);
pfrm.setUser("小张");
//调用处理
h3.handleRequest(pfrm);
//重新设置申请金额,再调用处理
pfrm.setFee(6000);
h3.handleRequest(pfrm);
//重新设置申请金额,再调用处理
pfrm.setFee(36000);
h3.handleRequest(pfrm);
}
}

总结

这种设计方式的好处,相当的通用和灵活,有了新业务,只需要添加实现新功能的对象就可以了,但是带来的缺陷就是可能会造成对象层次过多,或者出现较多的细粒度的对象,极端情况下,每次就扩展一个方法,会出现大量只处理一个功能的细粒度对象。

本文标题:设计模式-责任链模式

文章作者:王洪博

发布时间:2018年10月25日 - 19:10

最后更新:2019年09月12日 - 10:09

原始链接:http://whb1990.github.io/posts/b6c1490f.html

▄︻┻═┳一如果你喜欢这篇文章,请点击下方"打赏"按钮请我喝杯 ☕
0%