责任链模式基础
责任链模式基础
责任链模式
责任链模式定义
是一个请求有多个对象来处理,这些对象是一条链,但具体由哪个对象来处理,根据条件判断来确定,如果不能处理会传递给该链中的下一个对象,直到有对象处理它为止。
将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求。将这些接收对象串成一条链,并沿着这条链传递这个请求,直到链上的某个接收对象能够处理它为止。
以上定义来自《设计模式之美》
- Client(客户端):实例化一个处理器的链,在第一个链对象中调用 handleRequest 方法。
- Handle(处理器):抽象类,提供给实际处理器继承然后实现 handleRequst 方法,处理请求
- ConcreteHandler(具体处理器):继承了 handler 的类,同时实现 handleRequst 方法,负责处理业务逻辑类,不同业务模块有不同的 ConcreteHandler。
使用场景
- 有多个对象可以处理同一个请求,具体哪个对象处理该请求待运行时刻再确定
- 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求
- 可动态指定一组对象处理请求,客户端可以动态创建责任链来处理请求
责任链模式实际使用场景
拦截器
一条 chain,其中有一个处理者处理,chain 断开
- 聊天 Message 处理
- 流程审批
默认处理者要放在最后一个
过滤器
一条 chain,链上的处理者可以对输入数据进行处理,交由下一个处理
责任链拦截器模板 (参考 OKHttp)
Interceptor
1
2
3
4
5
6
7
8
9
10
11
12
13
public interface Interceptor<T, R> {
R intercept(Chain<T, R> chain) throws Exception;
// Chain作为容器,为Interceptor携带input参数
interface Chain<T, R> {
T request(); // 输入参数,可以定义成多个
// 某条链上的处理动作,input为输入数据,R为输出
R proceed(T input) throws Exception;
}
}
RealInterceptorChain
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
class RealInterceptorChain<T, R> implements Interceptor.Chain<T, R> {
private List<Interceptor> interceptors;
private int index;
private T input;
public RealInterceptorChain(List<Interceptor> interceptors, int index, T input) {
this.interceptors = interceptors;
this.index = index;
this.input = input;
}
@Override
public T request() {
return input;
}
@Override
public R proceed(T input) throws Exception {
if (interceptors == null) {
throw new IllegalArgumentException("chains must not null!");
}
if (index < 0) {
throw new IllegalArgumentException("index must be positive!");
}
if (index >= interceptors.size()) {
throw new IllegalArgumentException("should a default interceptor not call proceed() , interceptors size: " + interceptors.size() + " index: " + index);
}
// 每经过一个链条,就是一个新的RealInterceptorChain
RealInterceptorChain<T, R> next = new RealInterceptorChain<T, R>(interceptors, index + 1, input);
Interceptor<T, R> interceptor = interceptors.get(index);
return interceptor.intercept(next);
}
}
InterceptorHelper
1
2
3
4
5
6
7
8
9
10
11
public final class InterceptorHelper {
public static <T, R> R build(T input, List<Interceptor<T, R>> interceptors) {
RealInterceptorChain<T, R> chain = new RealInterceptorChain(interceptors, 0, input);
try {
return chain.proceed(input);
} catch (Exception e) {
}
return null;
}
}
最后一个 Interceptor 不要调用 chain.proceed,否则会数组越界异常
使用了责任链模式的库
- OkHttp
- ViewPump
https://github.com/InflationX/ViewPump
责任链应用
责任链模式案例 1- 流程审批
1
2
3
4
员工请求审批流程,
组长可以批假不超过2天,
项目经理可以批假不超过10天,
老板可以批假不超过30天的假。
普通的责任链
- 管理者
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
/**
* 管理者统称
*
* 员工请求审批流程: 组长可以批假不超过2天, 项目经理可以批假不超过10天, 老板可以批假不超过30天的假。
*/
public abstract class Manager {
protected String name;
private Manager successor;
public Manager(String name, Manager successor) {
this.name = name;
this.successor = successor;
}
public Manager getSuccessor() {
return successor;
}
/**
* 处理请假审批
*
* @param user 请假者
* @param day 请假天数
*/
public abstract boolean handleRequestApprove(String user, int day);
}
- 组长
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 组长
*/
public final class GroupManager extends Manager {
public GroupManager(String name, Manager successor) {
super(name, successor);
}
@Override
public boolean handleRequestApprove(String user, int day) {
if (day <= 2) {
System.out.println("组长" + name + "可以直接审批不超过2天的假");
return true;
} else {
Manager successor = getSuccessor();
if (successor == null) {
throw new IllegalArgumentException("组长" + name + "需要有自己的领导!");
}
return successor.handleRequestApprove(user, day);
}
}
}
- 项目经理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 项目经理
*/
public final class ProjectManager extends Manager {
public ProjectManager(String name, Manager successor) {
super(name, successor);
}
@Override
public boolean handleRequestApprove(String user, int day) {
if (day <= 10) {
System.out.println("项目经理" + name + "可以直接审批不超过10天的假");
return true;
} else {
Manager successor = getSuccessor();
if (successor == null) {
throw new IllegalArgumentException("项目经理" + name + "需要有自己的领导!");
}
return successor.handleRequestApprove(user, day);
}
}
}
- 老板
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 老板
*/
public final class BossManager extends Manager {
public BossManager(String name) {
super(name, null);
}
@Override
public boolean handleRequestApprove(String user, int day) {
if (day <= 30) {
System.out.println("老板" + name + "只能审批不超过30天的假");
return true;
} else {
System.out.println("兄弟啊凉了啊,请这么久,直接打包回家吧!");
return false;
}
}
}
- 测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public final class TestChains {
public static void main(String[] args) {
buildChains();
String user = "苦逼的猿";
boolean requestApprove = buildChains().handleRequestApprove(user, 33);
if (requestApprove) {
System.out.println("审批了");
} else {
System.out.println("没人审批");
}
}
private static Manager buildChains() {
Manager bossManager = new BossManager("曾大圣");
Manager projectMananger = new ProjectManager("Elain", bossManager);
Manager manager = new GroupManager("chencheng", projectMananger);
return manager;
}
}
类似 OkHttp Interceptor 方式
需要手动设置链的下一个处理者,用类似 OkHttp Interceptor 的责任链来优化下
- ManagerV2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// ManagerV2,类似OkHttp中Interceptor
public interface ManagerV2 {
/**
* 处理请假请求
* @param chain Chain,需要包含ManagerV2所需要的输入参数
* @return 是否有人审批请假请求
*/
boolean handleRequestApprove(Chain chain);
interface Chain { 类似OkHttp中Chain
// 输入参数1,类似OkHttp中Request
String getUser();
// 输入参数2
int getDay();
// 供ManagerV2在handleRequestApprove()调用,表示不处理该请求,交由Chain中的下一个处理者ManagerV2来处理
boolean proceed(String user, int day);
}
}
- RealChainManager,链 chain 的构造,即 chain 下一个处理者的调用
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
public final class RealChainManager implements ManagerV2.Chain {
List<ManagerV2> mManagerV2s;
private int index;
private String user;
private int day;
public RealChainManager(List<ManagerV2> managerV2s, int index, String user, int day) {
mManagerV2s = managerV2s;
this.index = index;
this.user = user;
this.day = day;
}
@Override
public String getUser() {
return user;
}
@Override
public int getDay() {
return day;
}
@Override
public boolean proceed(String user, int day) {
if (index > mManagerV2s.size()) {
System.out.println("无人审批,审批不了:" + index);
return false;
}
ManagerV2.Chain next = new RealChainManager(mManagerV2s, index + 1, user, day);
// 当前审批者
ManagerV2 managerV2 = mManagerV2s.get(index);
boolean b = managerV2.handleRequestApprove(next);
return b;
}
}
具体的管理者
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
// GroupManagerV2
public class GroupManagerV2 implements ManagerV2 {
@Override
public boolean handleRequestApprove(Chain chain) {
String user = chain.getUser();
int day = chain.getDay();
if (day <= 2) {
System.out.println("组长可以直接审批" + user + "不超过2天的假");
return true;
}
return chain.proceed(user, day);
}
}
// ProjectManagerV2
public class ProjectManagerV2 implements ManagerV2 {
@Override
public boolean handleRequestApprove(Chain chain) {
String user = chain.getUser();
int day = chain.getDay();
if (day <= 10) {
System.out.println("项目经理可以直接审批" + user + "不超过10天的假");
return true;
}
return chain.proceed(user, day);
}
}
// BossManagerV2
public class BossManagerV2 implements ManagerV2 {
@Override
public boolean handleRequestApprove(Chain chain) {
String user = chain.getUser();
int day = chain.getDay();
if (day <= 30) {
System.out.println("老板可以直接审批" + user + "不超过30天的假");
return true;
}
return false;
}
}
测试:
1
2
3
4
5
6
7
8
9
10
11
12
13
private static void testChain2() {
String user = "hacket";
int day = 35;
List<ManagerV2> managerV2s = new ArrayList<>();
managerV2s.add(new GroupManagerV2());
managerV2s.add(new ProjectManagerV2());
managerV2s.add(new BossManagerV2());
RealChainManager chain = new RealChainManager(managerV2s, 0, user, day); // 构造chain
boolean proceed = chain.proceed(user, day); // 交由链来处理,其中有一个处理,那么该链就终止
if (!proceed) {
System.out.println("无人审批啊");
}
}
责任链模式案例 2- 对这段文本进行加工过滤
假设这样的场景:传入了一段内容,需要对这段文本进行加工;比如过滤敏感词、错别字修改、最后署上版权等操作。
定义接口 TextProcessFilter
1
2
3
4
5
6
7
public interface TextProcessFilter {
Text doProcess(Chain chain);
interface Chain {
Text getInput();
Text proceed(Text originText);
}
}
RealTextProcessFilterChain
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
public class RealTextProcessFilterChain implements TextProcessFilter.Chain {
private List<TextProcessFilter> textProcessFilters;
private int index;
private Text input;
public RealTextProcessFilterChain(List<TextProcessFilter> textProcessFilters, int index, Text input) {
this.textProcessFilters = textProcessFilters;
this.index = index;
this.input = input;
}
@Override
public Text getInput() {
return input;
}
@Override
public Text proceed(Text originText) {
if (textProcessFilters == null) {
throw new IllegalArgumentException("textProcessFilters不能为空!");
}
if (index >= textProcessFilters.size()) {
throw new IllegalArgumentException("越界了:index:" + index + ",size:" + textProcessFilters.size());
}
TextProcessFilter.Chain next = new RealTextProcessFilterChain(textProcessFilters, index + 1, input);
TextProcessFilter textProcessFilter = textProcessFilters.get(index);
return textProcessFilter.doProcess(next);
}
}
实际的处理者
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
// 英文全部大写,ToUpperTextFilter
public class ToUpperTextFilter implements TextProcessFilter {
@Override
public Text doProcess(Chain chain) {
Text input = chain.getInput();
String s = input.text.toUpperCase();
input.text = s;
return chain.proceed(input);
}
}
// 过滤色情字符,YellowTextFilter
public class YellowTextFilter implements TextProcessFilter {
@Override
public Text doProcess(Chain chain) {
Text input = chain.getInput();
String text = input.text;
String result = text.replace("色", "***");
input.text = result;
return chain.proceed(input);
}
}
// 版权信息,CopyrightTextFilter
public class CopyrightTextFilter implements TextProcessFilter {
@Override
public Text doProcess(Chain chain) {
Text input = chain.getInput();
StringBuilder sb = new StringBuilder();
sb.append(input.text);
sb.append("-->>曾大圣,版权所有©️");
input.text = sb.toString();
return input; // 最后一个不要proceed了
}
}
测试:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private static void testToUpperTextFilter() {
List<TextProcessFilter> processFilters = new ArrayList<>();
processFilters.add(new ToUpperTextFilter());
processFilters.add(new YellowTextFilter());
processFilters.add(new CopyrightTextFilter());
Text text = new Text("你猜我是谁,我是hacket?,哈哈,颜色");
System.out.println("处理前:" + text.text);
RealTextProcessFilterChain chain = new RealTextProcessFilterChain(processFilters, 0, text);
Text proceedText = chain.proceed(text);
System.out.println("处理后:" + proceedText.text);
}
结果:
1
2
处理前:你猜我是谁,我是hacket?,哈哈,颜色
处理后:你猜我是谁,我是HACKET?,哈哈,颜***-->>曾大圣,版权所有©️
责任链模式案例 3- 网络请求错误码全局处理
- 错误码处理
接口 IErrorHandler 定义:
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
interface IErrorHandler {
@Throws(CustomHttpException::class)
fun handle(chain: Chain)
// 由Chain定义Handler需要处理的input参数,由proceed返回值为output,chain为一条链
interface Chain {
fun getErrCode(): Int // Handler的input
fun getErrMsg(): String // Handler的input
@Throws(CustomHttpException::class)
fun proceed(errCode: Int, errMsg: String) // 返回值可以定义ouput
}
companion object {
const val TAG = "net.error"
/**
* Token过期
*/
const val ERROR_TOKEN_EXPIRE = -2
/**
* 在其他设备登录
*/
const val ERROR_LOGIN_OTHER_DEVICE = -4
/**
* 用户被封禁
*/
const val ERROR_USER_BANNED = -5
}
}
RealErrorHandlerChain
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
class RealErrorHandlerChain(
private val mHandlerList: List<IErrorHandler>?,
private val index: Int,
private val errCode: Int,
private val errMsg: String) : IErrorHandler.Chain {
override fun getErrCode(): Int {
return errCode
}
override fun getErrMsg(): String {
return errMsg
}
@Throws(CustomHttpException::class)
override fun proceed(errCode: Int, errMsg: String) {
if (mHandlerList == null) {
throw IllegalArgumentException("mHandlerList不能为空!")
}
if (index >= mHandlerList.size) {
throw IllegalArgumentException("越界了:index:" + index + ",size:" + mHandlerList.size)
}
val next = RealErrorHandlerChain(mHandlerList, index + 1, errCode, errMsg)
val handler = mHandlerList[index]
handler.handle(next)
}
}
具体的 Handler
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
class LogoutErrorHandler : IErrorHandler {
@Throws(CustomHttpException::class)
override fun handle(chain: IErrorHandler.Chain) {
val errCode = chain.getErrCode()
val errMsg = chain.getErrMsg()
when (errCode) {
IErrorHandler.ERROR_TOKEN_EXPIRE,
IErrorHandler.ERROR_LOGIN_OTHER_DEVICE,
IErrorHandler.ERROR_USER_BANNED -> {
ToastUtils.showLong(errMsg)
gotoLoginPage()
LogUtils.e(TAG, "${anchor("handle")}token过期回到登录页面," +
"errCode=$errCode,errMsg=$errMsg")
}
else -> {
chain.proceed(errCode, errMsg)
}
}
}
private fun gotoLoginPage() {
UserCenterManager.logout(GlobalContext.getAppContext())
ARouter.getInstance()
.build(ARouterConstants.Login.ROUTER_PATH_ACTIVITY_LOGIN)
.withFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
.navigation()
}
}
class DefaultErrorHandler : IErrorHandler {
@Throws(CustomHttpException::class)
override fun handle(chain: IErrorHandler.Chain) {
val errCode = chain.getErrCode()
val errMsg = chain.getErrMsg()
LogUtils.w(IErrorHandler.TAG, "DefaultErrorHandler,errCode=$errCode,errMsg=$errMsg")
throw CustomHttpException(errMsg, errCode)
}
}
使用
1
2
3
4
5
List<IErrorHandler> handlers = new ArrayList<>();
handlers.add(new LogoutErrorHandler());
handlers.add(new DefaultErrorHandler());
RealErrorHandlerChain chain = new RealErrorHandlerChain(handlers, 0, error, errorMsg);
chain.proceed(error, errorMsg);
本文由作者按照 CC BY 4.0 进行授权