关于责任链模式在实际生产中的应用
一.背景
我司是做火车票抢票软件的,做抢票软件就少不了需要登录12306,近期12306风控比较严重,导致登录的时候老是需要换登录方式,常见的登录有登录态登录,扫码登录,用户名密码登录,只要有一个登录失败就会进行下一个登录方式,直到登录成功为止,而原先的代码所有的业务逻辑都耦合在一起,查看问题时需要查看全局代码,逻辑又比较复杂,分析问题的时候需要很长时间,现需要对该逻辑进行优化。
二.分析
2.1 分析
经过对代码的分析,决定采用责任链的模式对逻辑进行优化。
2.2什么是责任链模式
责任链模式(Chain of Responsibility)是一种处理请求的模式,它让多个处理器都有机会处理该请求,直到其中某个处理成功为止,看责任链的定义刚好符合我的需要。
三.代码编写
3.1编写登录处理接口
public interface LoginHandler<T> {
void doLogin(LoginContext<T> loginContext, LoginHandlerChain chain);
}
3.2创建登录执行链类
public class LoginHandlerChain implements LoginHandler {
private List<LoginHandler> handlerList;
private int position;
public void addLoginFilter(LoginHandler loginHandler) {
if (null == handlerList) {
handlerList = new ArrayList<>();
}
handlerList.add(loginHandler);
}
@Override
public void doLogin(LoginContext loginContext, LoginHandlerChain chain) {
//省略业务逻辑
if (loginContext.getFinished()||position >= handlerList.size()) {
return;
}
handlerList.get(position++).doLogin(loginContext, chain);
}
}
3.3创建存储登录上下文的类
public class LoginContext {
private boolean finished;
public boolean getFinished() {
return finished;
}
public void setFinished(boolean finished) {
this.finished = finished;
}
}
3.4创建登录态登录实现类
public class SessionLoginHandler implements LoginHandler<Browser> {
@Override
public void doLogin(LoginContext<Browser> ctx, LoginHandlerChain chain) {
//根据业务逻辑处理
if(登录态登录成功){
ctx.setFinished(true);
return;
}
chain.doLogin(context, chain);
}
}
3.5创建扫码登录实现类
public class ScanCodeLoginHandler implements LoginHandler<Broswer> {
@Override
public void doLogin(LoginContext<Broswer> ctx, LoginHandlerChain chain) {
//根据业务逻辑处理
if(扫码登录成功){
ctx.setFinished(true);
return;
}
chain.doLogin(context, chain);
}
}
3.6创建用户名密码实现类
public class UserNameLoginHandler implements LoginHandler<Broswer> {
@Override
public void doLogin(LoginContext<Broswer> ctx, LoginHandlerChain chain) {
//根据业务逻辑处理
if(用户名密码登录成功){
ctx.setFinished(true);
return;
}
chain.doLogin(context, chain);
}
}
3.7生成执行链
@Test
public void test2(){
LoginHandlerChain chain = new LoginHandlerChain();
chain.addLoginFilter(new SessionLoginHandler());
chain.addLoginFilter(new ScanCodeLoginHandler());
chain.addLoginFilter(new UserNameLoginHandler());
LoginContext context = new LoginContext<>();
chain.doLogin(context, chain);
}
四.总结
由于保密性原则,逻辑代码没有写,只是记录碰到相应场景应该如何使用相应的设计模式解决问题,当然我们真正的代码都是交给spring管理的,生成的责任链并且是可以实时刷新的,只需要更改配置就可以更换里面处理的顺序,其中返回的结果又使用的策略模式进行处理,由于之前文章记录过这里不做记录。