自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

巧妙利用 SpringBoot 責任連模式,讓編程事半功倍!

開發(fā) 前端
本文主要圍繞在 SpringBoot 中如何引入責任鏈設計模式,介紹了三種玩法,其中第二種用法最多,其次就是第一種,第三種用的比較少,第三種本質是一種鏈式寫法,可能理解上不如第一種直觀,但是效果是一樣的。

一、什么是責任鏈模式?

責任鏈模式(Chain of Responsibility Pattern),顧名思義,為請求者和接受者之間創(chuàng)建一條對象處理鏈路,避免請求發(fā)送者與接收者耦合在一起!

圖片

責任鏈模式,是一種實用性非常強的設計模式,比較典型的應用場景有:

  • Apache Tomcat 對 Encoding 編碼處理的處理
  • SpringBoot ??的攔截器、過濾器鏈
  • netty 中的處理鏈
  • 支付風控的機制
  • ?志處理級別

尤其是當程序的處理流程很長的時候,采用責任鏈設計模式,不僅實現(xiàn)優(yōu)雅,而且易復用可擴展!

今天我們就一起來了解一下在 SpringBoot 中如何應用責任鏈模式!

二、代碼實踐

在 SpringBoot 中,責任鏈模式的實踐方式有好幾種,今天我們主要抽三種實踐方式給大家介紹。

我們以某下單流程為例,將其切成多個獨立檢查邏輯,可能會經(jīng)過的數(shù)據(jù)驗證處理流程如下:

圖片

采用責任鏈設計模式來編程,代碼實踐如下!

2.1、方式一

首先,我們定義一個簡易版的下單對象OrderContext。

public class OrderContext {

    /**
     * 請求唯一序列ID
     */
    private String seqId;

    /**
     * 用戶ID
     */
    private String userId;

    /**
     * 產品skuId
     */
    private Long skuId;

    /**
     * 下單數(shù)量
     */
    private Integer amount;

    /**
     * 用戶收貨地址ID
     */
    private String userAddressId;

 //..set、get
}

然后,我們定義一個數(shù)據(jù)處理接口OrderHandleIntercept,用于標準化執(zhí)行!

public interface OrderHandleIntercept {

    /**
     * 指定執(zhí)行順序
     * @return
     */
    int sort();

    /**
     * 對參數(shù)進行處理
     * @param context
     * @return
     */
    OrderAddContext handle(OrderAddContext context);
}

接著,我們分別創(chuàng)建三個不同的接口實現(xiàn)類,并指定執(zhí)行順序,內容如下:

  • RepeatOrderHandleInterceptService:用于重復下單的邏輯驗證
  • ValidOrderHandleInterceptService:用于驗證請求參數(shù)是否合法
  • BankOrderHandleInterceptService:用于檢查客戶賬戶余額是否充足
@Component
public class RepeatOrderHandleInterceptService implements OrderHandleIntercept {

    @Override
    public int sort() {
        //用于重復下單的邏輯驗證,在執(zhí)行順序為1
        return 1;
    }

    @Override
    public OrderAddContext handle(OrderAddContext context) {
        System.out.println("通過seqId,檢查客戶是否重復下單");
        return context;
    }
}
@Component
public class ValidOrderHandleInterceptService implements OrderHandleIntercept {


    @Override
    public int sort() {
        //用于驗證請求參數(shù)是否合法,執(zhí)行順序為2
        return 2;
    }

    @Override
    public OrderAddContext handle(OrderAddContext context) {
        System.out.println("檢查請求參數(shù),是否合法,并且獲取客戶的銀行賬戶");
        return context;
    }
}
@Component
public class BankOrderHandleInterceptService implements OrderHandleIntercept {


    @Override
    public int sort() {
        //用于檢查客戶賬戶余額是否充足,在執(zhí)行順序為3
        return 3;
    }

    @Override
    public OrderAddContext handle(OrderAddContext context) {
        System.out.println("檢查銀行賬戶是否合法,調用銀行系統(tǒng)檢查銀行賬戶余額是否滿足下單金額");
        return context;
    }
}

再然后,我們還需要創(chuàng)建一個訂單數(shù)據(jù)驗證管理器OrderHandleChainService,用于管理這些實現(xiàn)類。

@Component
public class OrderHandleChainService implements ApplicationContextAware {

    private List<OrderHandleIntercept> handleList = new ArrayList<>();


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        //獲取指定的接口實現(xiàn)類,并按照sort進行排序,放入List中
        Map<String, OrderHandleIntercept> serviceMap = applicationContext.getBeansOfType(OrderHandleIntercept.class);
        handleList = serviceMap.values().stream()
                .sorted(Comparator.comparing(OrderHandleIntercept::sort))
                .collect(Collectors.toList());
    }

    /**
     * 執(zhí)行處理
     * @param context
     * @return
     */
    public OrderAddContext execute(OrderAddContext context){
        for (OrderHandleIntercept handleIntercept : handleList) {
            context =handleIntercept.handle(context);
        }
        return context;
    }
}

最后,我們編寫單元測試來看看效果如何!

@RunWith(SpringRunner.class)
@SpringBootTest
public class CalculatorServiceTest {

    @Autowired
    private OrderHandleChainService orderHandleChainService;

    @Test
    public void test(){
        orderHandleChainService.execute(new OrderAddContext());
    }
}

執(zhí)行結果如下:

通過seqId,檢查客戶是否重復下單
檢查請求參數(shù),是否合法,并且獲取客戶的銀行賬戶
檢查銀行賬戶是否合法,調用銀行系統(tǒng)檢查銀行賬戶余額是否滿足下單金額

如果需要繼續(xù)加驗證流程或者處理流程,只需要重新實現(xiàn)OrderHandleIntercept接口就行,其他的代碼無需改動!

當然,有的同學可能覺得這種方法用的不習慣,不喜歡通過sort()來指定順序,也可以通過如下方式進行手動add排序。

@Component
public class OrderHandleChainService {

    private List<OrderHandleIntercept> handleList = new ArrayList<>();

    @Autowired
    private ValidOrderHandleInterceptService validOrderHandleInterceptService;

    @Autowired
    private RepeatOrderHandleInterceptService repeatOrderHandleInterceptService;

    @Autowired
    private BankOrderHandleInterceptService bankOrderHandleInterceptService;

    @PostConstruct
    public void init(){
     //依次手動add對象
        handleList.add(repeatOrderHandleInterceptService);
        handleList.add(validOrderHandleInterceptService);
        handleList.add(bankOrderHandleInterceptService);
    }

    /**
     * 執(zhí)行處理
     * @param context
     * @return
     */
    public OrderAddContext execute(OrderAddContext context){
        for (OrderHandleIntercept handleIntercept : handleList) {
            context =handleIntercept.handle(context);
        }
        return context;
    }
}

2.2、方式二

第二種實現(xiàn)方式,就更簡單了,我們通過注解@Order來指定排序,代替手動方法排序sort(),操作方式如下:

/**
 * 指定注入順序為1
 *
 */
@Order(1)
@Component
public class RepeatOrderHandleInterceptService implements OrderHandleIntercept {


    //...省略
}
/**
 * 指定注入順序為2
 *
 */
@Order(2)
@Component
public class ValidOrderHandleInterceptService implements OrderHandleIntercept {


    //...省略
}
/**
 * 指定注入順序為3
 *
 */
@Order(3)
@Component
public class BankOrderHandleInterceptService implements OrderHandleIntercept {


    //...省略
}
@Component
public class OrderHandleChainService  {

 @Autowired
    private List<OrderHandleIntercept> handleList;

    /**
     * 執(zhí)行處理
     * @param context
     * @return
     */
    public OrderAddContext execute(OrderAddContext context){
        for (OrderHandleIntercept handleIntercept : handleList) {
            context =handleIntercept.handle(context);
        }
        return context;
    }
}

運行單元測試,你會發(fā)現(xiàn)結果與上面運行的結果一致,原因Springioc容器,支持通過Map或者List來直接注入對象,省去自己排序。

2.3、方式三

通過定義抽象類來實現(xiàn)責任鏈設計模式,還是以上面的案例為例,我們需要先定義一個抽象類,比如AbstractOrderHandle。

public abstract class AbstractOrderHandle {

    /**
     * 責任鏈,下一個鏈接節(jié)點
     */
    private AbstractOrderHandle next;

    /**
     * 執(zhí)行入口
     * @param context
     * @return
     */
    public OrderAddContext execute(OrderAddContext context){
        context = handle(context);
        // 判斷是否還有下個責任鏈節(jié)點,沒有的話,說明已經(jīng)是最后一個節(jié)點
        if(getNext() != null){
            getNext().execute(context);
        }
        return context;
    }

    /**
     * 對參數(shù)進行處理
     * @param context
     * @return
     */
    public abstract OrderAddContext handle(OrderAddContext context);


    public AbstractOrderHandle getNext() {
        return next;
    }

    public void setNext(AbstractOrderHandle next) {
        this.next = next;
    }
}

然后,分別創(chuàng)建三個處理類,并排好序號。

@Order(1)
@Component
public class RepeatOrderHandle extends AbstractOrderHandle {

    @Override
    public OrderAddContext handle(OrderAddContext context) {
        System.out.println("通過seqId,檢查客戶是否重復下單");
        return context;
    }
}
@Order(2)
@Component
public class ValidOrderHandle extends AbstractOrderHandle {

    @Override
    public OrderAddContext handle(OrderAddContext context) {
        System.out.println("檢查請求參數(shù),是否合法,并且獲取客戶的銀行賬戶");
        return context;
    }
}
@Order(3)
@Component
public class BankOrderHandle extends AbstractOrderHandle {

    @Override
    public OrderAddContext handle(OrderAddContext context) {
        System.out.println("檢查銀行賬戶是否合法,調用銀行系統(tǒng)檢查銀行賬戶余額是否滿足下單金額");
        return context;
    }
}

接著,創(chuàng)建一個責任鏈管理器,比如OrderHandleManager。

@Component
public class OrderHandleManager {

    @Autowired
    private List<AbstractOrderHandle> orderHandleList;


    @PostConstruct
    public void init(){
        //如果List沒有按照@Order注解方式排序,可以通過如下方式手動排序
        Collections.sort(orderHandleList, AnnotationAwareOrderComparator.INSTANCE);
        int size = orderHandleList.size();
        for (int i = 0; i < size; i++) {
            if(i == size -1){
                orderHandleList.get(i).setNext(null);
            } else {
                orderHandleList.get(i).setNext(orderHandleList.get(i + 1));
            }
        }

    }

    /**
     * 執(zhí)行處理
     * @param context
     * @return
     */
    public OrderAddContext execute(OrderAddContext context){
        context = orderHandleList.get(0).execute(context);
        return context;
    }
}

最后,我們編寫單元測試,來看看效果。

@RunWith(SpringRunner.class)
@SpringBootTest
public class CalculatorServiceTest {

    @Autowired
    private OrderHandleManager orderHandleManager;

    @Test
    public void test(){
        orderHandleManager.execute(new OrderAddContext());
    }

}

運行結果與預期一致!

通過seqId,檢查客戶是否重復下單
檢查請求參數(shù),是否合法,并且獲取客戶的銀行賬戶
檢查銀行賬戶是否合法,調用銀行系統(tǒng)檢查銀行賬戶余額是否滿足下單金額

三、小結

本文主要圍繞在 SpringBoot 中如何引入責任鏈設計模式,介紹了三種玩法,其中第二種用法最多,其次就是第一種,第三種用的比較少,第三種本質是一種鏈式寫法,可能理解上不如第一種直觀,但是效果是一樣的。

有效的使用責任鏈設計模式,可以顯著降低業(yè)務代碼的復雜度,可讀性更好,更容易擴展,希望對大家有幫助!

責任編輯:武曉燕 來源: 潘志的研發(fā)筆記
相關推薦

2022-10-08 07:31:59

Spring責任連模式

2021-07-12 07:08:54

責任鏈模式對象

2009-03-02 10:13:00

交換機端口模式

2021-12-24 07:50:45

責任鏈模式設計

2023-12-14 07:11:24

編程語言微服務

2009-04-22 09:50:00

TOMATO固件無線網(wǎng)絡

2010-07-16 10:23:28

Batch telne

2022-12-28 08:08:57

2012-03-28 13:28:56

Java設計模式

2009-10-22 09:52:41

域名郵箱安全

2013-12-09 10:46:24

2010-04-01 09:10:03

PHP設計模式責任鏈模式

2011-04-01 10:16:08

SQL ServerEXISTS結構

2022-11-01 08:46:20

責任鏈模式對象

2009-08-03 14:14:27

2022-07-12 07:33:47

ES類似連表查詢

2017-07-13 09:26:28

數(shù)據(jù)中心運營優(yōu)化

2021-12-03 23:14:49

Github插件開發(fā)

2018-11-19 15:06:23

Python算法

2020-09-16 11:10:33

Linux命令文件
點贊
收藏

51CTO技術棧公眾號