设计模式-从风控链理解责任链模式
前言
责任链是一种行为型模式。顾名思义,由多个有不同处理能力节点组成的一条执行链。当一个事件进来时,会判断当前节点是否有处理的能力,反之转入下一个节点进行处理。可以从支付的风控链这个场景,深入的理解责任链模式。
定义
责任链模式:包含了一些命令和一系列的处理对象。每一个处理对象决定了它能处理哪些命令对象,它也知道如何将它不能处理的命令对象传递给该链中的下一个处理对象。
如何理解
信用卡套现,花呗套现,白条套现,类似的名词对于我们来讲应该不陌生吧。在支付系统中会有一套风控系统,来避免发生类似的事情出现。而风控系统就是责任链模式的一种应用。
比如说给xxx商户配置的风控规则是:
TOP |
信用卡 |
花呗 |
白条 |
---|---|---|---|
木屋烧烤 |
500/日 |
300/日 |
300/日 |
当用户向商家付款时,会根据不同的支付方式,来判断是否触发风控条件。如果达到触发条件则不允许使用该方式支付。来避免发生信用卡套现类似的事情。
我们写个简单的风控程序来理解一下:
UML
代码示例
RiskHandler
public abstract class RiskHandler {
/**
* 支付方式
*/
private String payType;
private RiskHandler nextHandler;
public RiskHandler(String payType) {
this.payType = payType;
}
/**
* 是否能支付
* @param order 订单
*/
protected abstract boolean canPay(Order order);
/**
* 处理器
* @param order 订单
* @return 返回true 或者 false
*/
public final boolean handler(Order order){
if(order.getPayType().equals(this.payType)){
return this.canPay(order);
}else {
if (this.nextHandler != null){
return this.nextHandler.handler(order);
}else{
throw new IllegalArgumentException("支付方式有误");
}
}
}
public void setNextHandler(RiskHandler handler){
this.nextHandler = handler;
}
}
CreditHandler
public class CreditHandler extends RiskHandler {
/**
* 500 限额
*/
private BigDecimal limitAmount = BigDecimal.valueOf(500);
public CreditHandler() {
super(PayTypeEnum.CREDIT.getPayType());
}
@Override
protected boolean canPay(Order order) {
if(order.getAmount().compareTo(limitAmount) < 0){
limitAmount = limitAmount.subtract(order.getAmount());
return true;
}else {
return false;
}
}
}
HuabeiHandler
public class HuabeiHandler extends RiskHandler {
/**
* 300 限额
*/
private BigDecimal limitAmount = BigDecimal.valueOf(300);
public HuabeiHandler() {
super(PayTypeEnum.HUA_BEI.getPayType());
}
@Override
protected boolean canPay(Order order) {
if(order.getAmount().compareTo(limitAmount) < 0){
limitAmount = limitAmount.subtract(order.getAmount());
return true;
}else {
return false;
}
}
}
BaiTiaoHandler
public class BaiTiaoHandler extends RiskHandler {
/**
* 300 限额
*/
private BigDecimal limitAmount = BigDecimal.valueOf(300);
public BaiTiaoHandler() {
super(PayTypeEnum.BAI_TIAO.getPayType());
}
@Override
protected boolean canPay(Order order) {
if(order.getAmount().compareTo(limitAmount) < 0){
limitAmount = limitAmount.subtract(order.getAmount());
return true;
}else {
return false;
}
}
}
Order
public interface Order {
/**
* 获取支付方式
* @return 支付方式
*/
String getPayType();
/**
* 获取订单金额
* @return 订单金额
*/
BigDecimal getAmount();
}
ConsumeOrder
public class ConsumeOrder implements Order {
private String payType;
private BigDecimal amount;
public ConsumeOrder(String payType, BigDecimal amount) {
this.payType = payType;
this.amount = amount;
}
@Override
public String getPayType() {
return this.payType;
}
@Override
public BigDecimal getAmount() {
return this.amount;
}
}
PayTypeEnum
public enum PayTypeEnum {
/**
* 花呗
*/
HUA_BEI("hua_bei"),
/**
* 白条
*/
BAI_TIAO("bai_tiao"),
/**
* 信用卡
*/
CREDIT("credit"),
;
private String payType;
PayTypeEnum(String payType) {
this.payType = payType;
}
public String getPayType() {
return payType;
}
}
PayRiskControlService
public class PayRiskControlService {
public boolean canPay(Order order){
// 设置风控
RiskHandler creditHandler = new CreditHandler();
RiskHandler huabeiHandler = new HuabeiHandler();
RiskHandler baiTiaoHandler = new BaiTiaoHandler();
creditHandler.setNextHandler(huabeiHandler);
huabeiHandler.setNextHandler(baiTiaoHandler);
return creditHandler.handler(order);
}
}
Test
public class Test {
public static void main(String[] args) {
// 花呗订单
ConsumeOrder huabeiOrder = new ConsumeOrder(
PayTypeEnum.HUA_BEI.getPayType(), BigDecimal.valueOf(200)
);
// 白条订单
ConsumeOrder baitiaoOrder = new ConsumeOrder(
PayTypeEnum.BAI_TIAO.getPayType(), BigDecimal.valueOf(301)
);
// 加载风控系统
PayRiskControlService riskControlService = new PayRiskControlService();
// 创建订单
boolean canPayOfHuabei = riskControlService.canPay(huabeiOrder);
boolean canPayOfBaitiao = riskControlService.canPay(baitiaoOrder);
System.out.println("canPayOfHuabei = " + canPayOfHuabei);
System.out.println("canPayOfBaitiao = " + canPayOfBaitiao);
}
}
测试结果
ConsumeOrder{payType='hua_bei', amount=200} canPay: true
ConsumeOrder{payType='bai_tiao', amount=301} canPay: false
优点
- 降低耦合度,将请求和处理分开。
- 简化了对象,是对象不需要知道链的结构。
- 增强给对象指派职责的灵活性,通过改变链内的成员或者调动他们的次序,运行动态的新增或者删除责任。
- 增加新的处理类很方便。
缺点
- 不能保证请求一定被接收
- 系统性能将受到一定影响,而且在调试代码时不太方便,可能会造成循环调用。
- 可能不容易观察运行时的特征,有碍于除错。
应用场景
- 有多个对象可以处理同一个请求,具体是哪个对象处理由该请求运行时刻自动确定。
- 在不明确接受者的情况下,向多个对象中的一个提交一个请求。
- 可以动态指定一组对象处理请求。
责任链模式的两种情况
纯的职责链模式
一个请求必须被某一个处理者对象所接收,且一个具体处理者对某个请求的处理只能采用以下两种行为之一:自己处理(承担责任),把责任推给下家处理。
不纯的职责链模式
允许出现某一个具体处理者对象在承担了请求的一部分责任后又将剩余的责任传给下家的情况,且一个请求可以最终不被任何接收端对象所接收。比如说,多级审核,登录安全监测。
注意的点
链中节点数量需要控制,避免出现超长链的情况,一般的做法是在Handler中设置一个最大节点数量,在setNext方法中判断是否已经是超过其阈值,超过则不允许该链建立,避免无意识地破坏系统性能。
参考文章
- 设计模式之禅道第二版
- 责任链设计模式|菜鸟教程
结尾
如果觉得对你有帮助,可以多多评论,多多点赞哦,也可以到我的主页看看,说不定有你喜欢的文章,也可以随手点个关注哦,谢谢。
我是不一样的科技宅,每天进步一点点,体验不一样的生活。我们下期见!
- .Net Core Runtime安装说明
- 【专知-Deeplearning4j深度学习教程02】用ND4J自己动手实现RBM: 图文+代码
- 【专知-Deeplearning4j深度学习教程03】使用多层神经网络分类MNIST数据集:图文+代码
- TypeScript 1.6发布:完全支持React/JSX
- 【专知-Java Deeplearning4j深度学习教程04】使用CNN进行文本分类:图文+代码
- sql server之数据库语句优化
- 【专知-Java Deeplearning4j深度学习教程05】无监督特征提取神器—AutoEncoder:图文+代码
- 平衡树初阶——AVL平衡二叉查找树+三大平衡树(Treap + Splay + SBT)模板【超详解】
- HDU 2689 Sort it【树状数组】
- BZOJ 1800: [Ahoi2009]fly 飞行棋【思维题,n^4大暴力】
- Vijos P1066 弱弱的战壕【多解,线段树,暴力,树状数组】
- GeetTest~下一代验证(附C#案例)
- [接口测试 - http.client篇] 17 http.client之入门级接口测试框架
- 评论JS插件~多说+畅言
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Centos7安装ovs
- 好用-除了Console.log()之外的JS日志打印输出方式
- 解数独
- python编写断点续传下载软件
- cookie和session
- 自建KMS服务器 | 持续激活Windows
- 路由交换之静态路由
- Java面试基本问题
- 利用redis写webshell
- python富文本XSS过滤器
- PHP Multipart/form-data remote DOS 防御方案研究
- Kubernetes Python Client
- 对JiaThis Flash XSS的挖掘与分析
- Spark 3.0.1 Structured Streaming 提交程序异常解决
- 一起来探索下小程序包的魔数