当前位置:首页 > 人工智能

巧妙的运用责任链模式,让你的代码高出一个逼格!

本文转载自微信公众号「Java极客技术」,巧妙作者鸭血粉丝。运代码转载本文请联系Java极客技术公众号。用责

一、任链让介绍

什么是模式责任链模式?(Chain of Responsibility Pattern),简单的高出个逼格说,为请求者和接受者之间创建一条对象处理链路,巧妙避免请求发送者与接收者耦合在一起!

例如,运代码如下图:

从设计的用责角度看,责任链模式涉及到四个角色:

请求角色:可以是任链让外部的请求或者内部的请求,最终体现就是模式一个请求数据体; 抽象处理器角色:定义处理的一些基本的规范; 具体处理器角色:实现或者继承抽象处理器,完成具体的高出个逼格计算任务; 接着角色:用于接受请求数据最终的处理结果;

下面我们一起来看看具体的实际应用!

二、示例

在实际开发中,巧妙经常避免不了会与其他公司进行接口对接,运代码绝大部分请求参数都是用责经过加密处理再发送到互联网上,下面我们以对请求参数进行验证、封装处理为例,来诠释责任链模式的玩法,实现过程如下!

我们先编写一个加密工具类,采用AES加密算法

public class AESUtil {      private static Logger log = LoggerFactory.getLogger(AESUtil.class);     private static final String AES = "AES";     private static final String AES_CVC_PKC = "AES/CBC/PKCS7Padding";     static {          Security.addProvider(new BouncyCastleProvider());     }     /**      * 加密      * @param content      * @param key      * @return      * @throws Exception      */     public static String encrypt(String content, String key) {          try {              SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), AES);             Cipher cipher = Cipher.getInstance(AES_CVC_PKC);             IvParameterSpec iv = new IvParameterSpec(new byte[16]);             cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, iv);             byte[] encrypted = cipher.doFinal(content.getBytes());             return Base64.getEncoder().encodeToString(encrypted);         }  catch (Exception e) {              log.warn("AES加密失败,参数:{ },服务器租用错误信息:{ }", content, ExceptionUtils.getStackTrace(e));             return "";         }     }     /**      * 解密      * @param content      * @param key      * @return      * @throws Exception      */     public static String decrypt(String content, String key) {          try {              SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), AES);             Cipher cipher = Cipher.getInstance(AES_CVC_PKC);             IvParameterSpec iv = new IvParameterSpec(new byte[16]);             cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, iv);             byte[] encrypted = Base64.getDecoder().decode(content);             byte[] original = cipher.doFinal(encrypted);             return new String(original, "UTF-8");         } catch (Exception e) {              log.warn("AES解密失败,参数:{ },错误信息:{ }", content, ExceptionUtils.getStackTrace(e));             return "";         }     }     public static void main(String[] args) throws Exception {          String key = "1234567890123456";         String content = "{ \"userCode\":\"zhangsan\",\"userPwd\":\"123456\"}";         String encryptContext = encrypt(content, "1234567890123456");         System.out.println("加密后的内容:" + encryptContext);         String decryptContext = decrypt(encryptContext, key);         System.out.println("解密后的内容:" + decryptContext);     } } 

执行结果如下:

加密后的内容:5ELORDsYKxCz6Ec377udct7dBMI74ZtJDCFL4B3cpoBsPC8ILH/aiaRFnZa/oTC5 解密后的内容:{ "userCode":"zhangsan","userPwd":"123456"} 

其中加密后的内容可以看作为请求者传过来的参数!

同时,再创建一个上下文实体类ServiceContext,用于数据记录 /**  * 上下文  */ public class ServiceContext {      /**      * 请求参数      */     private String requestParam;     /**      * 解密后的数据      */     private String jsonData;     /**      * 用户账号      */     private String userCode;     /**      * 用户密码      */     private String userPwd;     //省略set\get     public ServiceContext() {      }     public ServiceContext(String requestParam) {          this.requestParam = requestParam;     } }  然后,创建一个处理器接口HandleIntercept public interface HandleIntercept {      /**      * 对参数进行处理      * @param context      * @return      */     ServiceContext handle(ServiceContext context); }  紧接着,创建两个处理器实现类,用于参数解密、业务数据验证 /**  * 解密请求数据  */ public class DecodeDataHandle implements HandleIntercept {      private String key = "1234567890123456";     @Override     public ServiceContext handle(ServiceContext context) {          String jsonData = AESUtil.decrypt(context.getRequestParam(), key);         if(StringUtils.isEmpty(jsonData)){              throw new IllegalArgumentException("解密失败");         }         context.setJsonData(jsonData);         return context;     } }  /**  * 验证业务数据并封装  */ public class ValidDataHandle implements HandleIntercept {      @Override     public ServiceContext handle(ServiceContext context) {          String jsonData = context.getJsonData();         JSONObject jsonObject = JSONObject.parseObject(jsonData);         if(!jsonObject.containsKey("userCode")){              throw new IllegalArgumentException("userCode不能为空");         }         context.setUserCode(jsonObject.getString("userCode"));         if(!jsonObject.containsKey("userPwd")){              throw new IllegalArgumentException("userPwd不能为空");         }         context.setUserPwd(jsonObject.getString("userPwd"));         return context;     } } 

最后创建一个处理链路管理器HandleChain

/**  * 请求处理链路管理器  */ public class HandleChain {      private List<HandleIntercept> handleInterceptList = new ArrayList<>();     /**      * 添加处理器      * @param handleIntercept      */     public void addHandle(HandleIntercept handleIntercept){          handleInterceptList.add(handleIntercept);     }     /**      * 执行处理      * @param context      * @return      */     public ServiceContext execute(ServiceContext context){          if(!handleInterceptList.isEmpty()){              for (HandleIntercept handleIntercept : handleInterceptList) {                  context =handleIntercept.handle(context);             }         }         return context;     } } 

写完之后,我们编写一个测试类ChainClientTest

public class ChainClientTest {      public static void main(String[] args) {          //获取请求参数         String requestParam = "5ELORDsYKxCz6Ec377udct7dBMI74ZtJDCFL4B3cpoBsPC8ILH/aiaRFnZa/oTC5";         //封装请求参数         ServiceContext serviceContext = new ServiceContext(requestParam);         //添加处理链路         HandleChain handleChain = new HandleChain();         handleChain.addHandle(new DecodeDataHandle());//解密处理         handleChain.addHandle(new ValidDataHandle());//数据验证处理         //执行处理链,获取处理结果         serviceContext = handleChain.execute(serviceContext);         System.out.println("处理结果:" + JSONObject.toJSONString(serviceContext));     } } 

执行之后结果如下:

处理结果:{ "jsonData":"{ \"userCode\":\"zhangsan\",\"userPwd\":\"123456\"}","requestParam":"5ELORDsYKxCz6Ec377udct7dBMI74ZtJDCFL4B3cpoBsPC8ILH/aiaRFnZa/oTC5","userCode":"zhangsan","userPwd":"123456"} 

可以很清晰的看到,从请求者发送数据经过处理器链路之后,数据都封装到上下文中去了!

如果想继续验证用户和密码是否合法,可以继续添加新的处理器,即可完成数据的处理验证!

如果是传统的方法,可能就是多个if,进行嵌套,类似如下:

if(condition){      if(condition){          if(condition){     //业务处理         }     } } 

这种模式,最大的弊端就是可读性非常差,云服务器提供商而且代码不好维护!

而责任链是从接口层进行封装处理和判断,可扩展性非常强!

三、应用

责任链模式的使用场景,这个就不多说了,最典型的就是 Servlet 中的 Filter,有了上面的分析,大家应该也可以理解 Servlet 中责任链模式的工作原理了,然后为什么一个一个的 Filter 需要配置在 web.xml 中,其实本质就是将 filter 注册到处理器中。

public class TestFilter implements Filter{      public void doFilter(ServletRequest request, ServletResponse response,             FilterChain chain) throws IOException, ServletException {          chain.doFilter(request, response);     }     public void destroy() { }     public void init(FilterConfig filterConfig) throws ServletException { } } 

四、总结

既然责任链模式这么好用,那什么时候用责任链模式?

在系统设计的时候,如果每个 if 都有一个统一的抽象,例如参数加密、系统数据验证、业务参数验证等等处理,可以将其抽象,使用对象处理进行链式调用,不仅实现优雅,而且易复用可扩展。

五、参考

1、高防服务器五月的仓颉 - 责任链模式

分享到:

滇ICP备2023006006号-16