
前言
責任鍊是一種行為型模式。顧名思義,由多個有不同處理能力節點組成的一條執行鍊。當一個事件進來時,會判斷目前節點是否有處理的能力,反之轉入下一個節點進行處理。可以從支付的風控鍊這個場景,深入的了解責任鍊模式。
定義
責任鍊模式:包含了一些指令和一系列的處理對象。每一個處理對象決定了它能處理哪些指令對象,它也知道如何将它不能處理的指令對象傳遞給該鍊中的下一個處理對象。
如何了解
信用卡套現,花呗套現,白條套現,類似的名詞對于我們來講應該不陌生吧。在支付系統中會有一套風控系統,來避免發生類似的事情出現。而風控系統就是責任鍊模式的一種應用。
比如說給xxx商戶配置的風控規則是:
TOP | 信用卡 | 花呗 | 白條 |
---|---|---|---|
木屋燒烤 | 500/日 | 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方法中判斷是否已經是超過其門檻值,超過則不允許該鍊建立,避免無意識地破壞系統性能。
參考文章
- 設計模式之禅道第二版
- 責任鍊設計模式|菜鳥教程
結尾
如果覺得對你有幫助,可以多多評論,多多點贊哦,也可以到我的首頁看看,說不定有你喜歡的文章,也可以随手點個關注哦,謝謝。