偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

責(zé)任鏈實(shí)戰(zhàn)的高級用法:多級校驗(yàn)、工作流,這樣寫代碼才足夠優(yōu)雅!

開發(fā) 前端
super.getConfig().getDown()是獲取AbstractCheckHandler處理器對象中保存的配置信息,如果處理器配置了降級,則跳過該處理器,調(diào)用super.next()執(zhí)行下一個處理器邏輯。

責(zé)任鏈模式,簡而言之,就是將多個操作組裝成一條鏈路進(jìn)行處理。請求在鏈路上傳遞,鏈路上的每一個節(jié)點(diǎn)就是一個處理器,每個處理器都可以對請求進(jìn)行處理,或者傳遞給鏈路上的下一個處理器處理。

應(yīng)用場景

責(zé)任鏈模式的應(yīng)用場景,在實(shí)際工作中,通常有如下兩種應(yīng)用場景。

  • 操作需要經(jīng)過一系列的校驗(yàn),通過校驗(yàn)后才執(zhí)行某些操作。
  • 工作流。企業(yè)中通常會制定很多工作流程,一級一級的去處理任務(wù)。

下面通過兩個案例來學(xué)習(xí)一下責(zé)任鏈模式。

案例一:創(chuàng)建商品多級校驗(yàn)場景

以創(chuàng)建商品為例,假設(shè)商品創(chuàng)建邏輯分為以下三步完成:①創(chuàng)建商品、②校驗(yàn)商品參數(shù)、③保存商品。

第②步校驗(yàn)商品又分為多種情況的校驗(yàn),必填字段校驗(yàn)、規(guī)格校驗(yàn)、價格校驗(yàn)、庫存校驗(yàn)等等。這些檢驗(yàn)邏輯像一個流水線,要想創(chuàng)建出一個商品,必須通過這些校驗(yàn)。如下流程圖所示:

圖片圖片

偽代碼如下:

創(chuàng)建商品步驟,需要經(jīng)過一系列的參數(shù)校驗(yàn),如果參數(shù)校驗(yàn)失敗,直接返回失敗的結(jié)果;通過所有的參數(shù)校驗(yàn)后,最終保存商品信息。

圖片圖片

如上代碼看起來似乎沒什么問題,它非常工整,而且代碼邏輯很清晰。

PS:我沒有把所有的校驗(yàn)代碼都羅列在一個方法里,那樣更能產(chǎn)生對比性,但我覺得抽象并分離單一職責(zé)的函數(shù)應(yīng)該是每個程序員最基本的規(guī)范!

但是隨著業(yè)務(wù)需求不斷地疊加,相關(guān)的校驗(yàn)邏輯也越來越多,新的功能使代碼越來越臃腫,可維護(hù)性較差。更糟糕的是,這些校驗(yàn)組件不可復(fù)用,當(dāng)你有其他需求也需要用到一些校驗(yàn)時,你又變成了Ctrl+C , Ctrl+V程序員,系統(tǒng)的維護(hù)成本也越來越高。如下圖所示:

圖片圖片

偽代碼同上,這里就不贅述了。

終于有一天,你忍無可忍了,決定重構(gòu)這段代碼。

使用責(zé)任鏈模式優(yōu)化:創(chuàng)建商品的每個校驗(yàn)步驟都可以作為一個單獨(dú)的處理器,抽離為一個單獨(dú)的類,便于復(fù)用。這些處理器形成一條鏈?zhǔn)秸{(diào)用,請求在處理器鏈上傳遞,如果校驗(yàn)條件不通過,則處理器不再向下傳遞請求,直接返回錯誤信息;若所有的處理器都通過檢驗(yàn),則執(zhí)行保存商品步驟。

圖片圖片

案例一實(shí)戰(zhàn):責(zé)任鏈模式實(shí)現(xiàn)創(chuàng)建商品校驗(yàn)

UML圖:一覽眾山小

圖片圖片

AbstractCheckHandler表示處理器抽象類,負(fù)責(zé)抽象處理器行為。其有3個子類,分別是:

  • NullValueCheckHandler:空值校驗(yàn)處理器
  • PriceCheckHandler:價格校驗(yàn)處理
  • StockCheckHandler:庫存校驗(yàn)處理器

AbstractCheckHandler 抽象類中, handle()定義了處理器的抽象方法,其子類需要重寫handle()方法以實(shí)現(xiàn)特殊的處理器校驗(yàn)邏輯;

protected ProductCheckHandlerConfig config 是處理器的動態(tài)配置類,使用protected聲明,每個子類處理器都持有該對象。該對象用于聲明當(dāng)前處理器、以及當(dāng)前處理器的下一個處理器nextHandler,另外也可以配置一些特殊屬性,比如說接口降級配置、超時時間配置等。

AbstractCheckHandler nextHandler 是當(dāng)前處理器持有的下一個處理器的引用,當(dāng)前處理器執(zhí)行完畢時,便調(diào)用nextHandler執(zhí)行下一處理器的handle()校驗(yàn)方法;

protected Result next() 是抽象類中定義的,執(zhí)行下一個處理器的方法,使用protected聲明,每個子類處理器都持有該對象。當(dāng)子類處理器執(zhí)行完畢(通過)時,調(diào)用父類的方法執(zhí)行下一個處理器nextHandler。

HandlerClient 是執(zhí)行處理器鏈路的客戶端,HandlerClient.executeChain()方法負(fù)責(zé)發(fā)起整個鏈路調(diào)用,并接收處理器鏈路的返回值。

擼起袖子開始擼代碼吧 !

商品參數(shù)對象:保存商品的入?yún)?/span>

ProductVO是創(chuàng)建商品的參數(shù)對象,包含商品的基礎(chǔ)信息。并且其作為責(zé)任鏈模式中多個處理器的入?yún)?,多個處理器都以ProductVO為入?yún)⑦M(jìn)行特定的邏輯處理。實(shí)際業(yè)務(wù)中,商品對象特別復(fù)雜。咱們化繁為簡,簡化商品參數(shù)如下:

/**
 * 商品對象
 */
@Data
@Builder
publicclass ProductVO {
    /**
     * 商品SKU,唯一
     */
    private Long skuId;
    /**
     * 商品名稱
     */
    private String skuName;
    /**
     * 商品圖片路徑
     */
    private String Path;
    /**
     * 價格
     */
    private BigDecimal price;
    /**
     * 庫存
     */
    private Integer stock;
}

抽象類處理器:抽象行為,子類共有屬性、方法

AbstractCheckHandler:處理器抽象類,并使用@Component注解注冊為由Spring管理的Bean對象,這樣做的好處是,我們可以輕松的使用Spring來管理這些處理器Bean。

/**
 * 抽象類處理器
 */
@Component
publicabstractclass AbstractCheckHandler {

    /**
     * 當(dāng)前處理器持有下一個處理器的引用
     */
    @Getter
    @Setter
    protected AbstractCheckHandler nextHandler;


    /**
     * 處理器配置
     */
    @Setter
    @Getter
    protected ProductCheckHandlerConfig config;

    /**
     * 處理器執(zhí)行方法
     * @param param
     * @return
     */
    public abstract Result handle(ProductVO param);

    /**
     * 鏈路傳遞
     * @param param
     * @return
     */
    protected Result next(ProductVO param) {
        //下一個鏈路沒有處理器了,直接返回
        if (Objects.isNull(nextHandler)) {
            return Result.success();
        }

        //執(zhí)行下一個處理器
        return nextHandler.handle(param);
    }

}

在AbstractCheckHandler抽象類處理器中,使用protected聲明子類可見的屬性和方法。使用 @Component注解,聲明其為Spring的Bean對象,這樣做的好處是可以利用Spring輕松管理所有的子類,下面會看到如何使用。抽象類的屬性和方法說明如下:

  • public abstract Result handle():表示抽象的校驗(yàn)方法,每個處理器都應(yīng)該繼承AbstractCheckHandler抽象類處理器,并重寫其handle方法,各個處理器從而實(shí)現(xiàn)特殊的校驗(yàn)邏輯,實(shí)際上就是多態(tài)的思想。
  • protected ProductCheckHandlerConfig config:表示每個處理器的動態(tài)配置類,可以通過“配置中心”動態(tài)修改該配置,實(shí)現(xiàn)處理器的“動態(tài)編排”和“順序控制”。配置類中可以配置處理器的名稱、下一個處理器、以及處理器是否降級等屬性。
  • protected AbstractCheckHandler nextHandler:表示當(dāng)前處理器持有下一個處理器的引用,如果當(dāng)前處理器handle()校驗(yàn)方法執(zhí)行完畢,則執(zhí)行下一個處理器nextHandler的handle()校驗(yàn)方法執(zhí)行校驗(yàn)邏輯。
  • protected Result next(ProductVO param):此方法用于處理器鏈路傳遞,子類處理器執(zhí)行完畢后,調(diào)用父類的next()方法執(zhí)行在config 配置的鏈路上的下一個處理器,如果所有處理器都執(zhí)行完畢了,就返回結(jié)果了。

ProductCheckHandlerConfig配置類 :

/**
 * 處理器配置類
 */
@AllArgsConstructor
@Data
public class ProductCheckHandlerConfig {
    /**
     * 處理器Bean名稱
     */
    private String handler;
    /**
     * 下一個處理器
     */
    private ProductCheckHandlerConfig next;
    /**
     * 是否降級
     */
    private Boolean down = Boolean.FALSE;
}

子類處理器:處理特有的校驗(yàn)邏輯

AbstractCheckHandler抽象類處理器有3個子類分別是:

  • NullValueCheckHandler:空值校驗(yàn)處理器
  • PriceCheckHandler:價格校驗(yàn)處理
  • StockCheckHandler:庫存校驗(yàn)處理器

各個處理器繼承AbstractCheckHandler抽象類處理器,并重寫其handle()處理方法以實(shí)現(xiàn)特有的校驗(yàn)邏輯。

NullValueCheckHandler:空值校驗(yàn)處理器。針對性校驗(yàn)創(chuàng)建商品中必填的參數(shù)。如果校驗(yàn)未通過,則返回錯誤碼ErrorCode,責(zé)任鏈在此截斷(停止),創(chuàng)建商品返回被校驗(yàn)住的錯誤信息。注意代碼中的降級配置!

super.getConfig().getDown()是獲取AbstractCheckHandler處理器對象中保存的配置信息,如果處理器配置了降級,則跳過該處理器,調(diào)用super.next()執(zhí)行下一個處理器邏輯。

同樣,使用@Component注冊為由Spring管理的Bean對象,

/**
 * 空值校驗(yàn)處理器
 */
@Component
publicclass NullValueCheckHandler extends AbstractCheckHandler{

    @Override
    public Result handle(ProductVO param) {
        System.out.println("空值校驗(yàn) Handler 開始...");
        
        //降級:如果配置了降級,則跳過此處理器,執(zhí)行下一個處理器
        if (super.getConfig().getDown()) {
            System.out.println("空值校驗(yàn) Handler 已降級,跳過空值校驗(yàn) Handler...");
            returnsuper.next(param);
        }
        
        //參數(shù)必填校驗(yàn)
        if (Objects.isNull(param)) {
            return Result.failure(ErrorCode.PARAM_NULL_ERROR);
        }
        //SkuId商品主鍵參數(shù)必填校驗(yàn)
        if (Objects.isNull(param.getSkuId())) {
            return Result.failure(ErrorCode.PARAM_SKU_NULL_ERROR);
        }
        //Price價格參數(shù)必填校驗(yàn)
        if (Objects.isNull(param.getPrice())) {
            return Result.failure(ErrorCode.PARAM_PRICE_NULL_ERROR);
        }
        //Stock庫存參數(shù)必填校驗(yàn)
        if (Objects.isNull(param.getStock())) {
            return Result.failure(ErrorCode.PARAM_STOCK_NULL_ERROR);
        }
        
        System.out.println("空值校驗(yàn) Handler 通過...");
        
        //執(zhí)行下一個處理器
        returnsuper.next(param);
    }
}

PriceCheckHandler:價格校驗(yàn)處理。針對創(chuàng)建商品的價格參數(shù)進(jìn)行校驗(yàn)。這里只是做了簡單的判斷價格>0的校驗(yàn),實(shí)際業(yè)務(wù)中比較復(fù)雜,比如“價格門”這些防范措施等。

/**
 * 價格校驗(yàn)處理器
 */
@Component
publicclass PriceCheckHandler extends AbstractCheckHandler{
    @Override
    public Result handle(ProductVO param) {
        System.out.println("價格校驗(yàn) Handler 開始...");

        //非法價格校驗(yàn)
        boolean illegalPrice =  param.getPrice().compareTo(BigDecimal.ZERO) <= 0;
        if (illegalPrice) {
            return Result.failure(ErrorCode.PARAM_PRICE_ILLEGAL_ERROR);
        }
        //其他校驗(yàn)邏輯...

        System.out.println("價格校驗(yàn) Handler 通過...");

        //執(zhí)行下一個處理器
        returnsuper.next(param);
    }
}

StockCheckHandler:庫存校驗(yàn)處理器。針對創(chuàng)建商品的庫存參數(shù)進(jìn)行校驗(yàn)。

/**
 * 庫存校驗(yàn)處理器
 */
@Component
publicclass StockCheckHandler extends AbstractCheckHandler{
    @Override
    public Result handle(ProductVO param) {
        System.out.println("庫存校驗(yàn) Handler 開始...");

        //非法庫存校驗(yàn)
        boolean illegalStock = param.getStock() < 0;
        if (illegalStock) {
            return Result.failure(ErrorCode.PARAM_STOCK_ILLEGAL_ERROR);
        }
        //其他校驗(yàn)邏輯..

        System.out.println("庫存校驗(yàn) Handler 通過...");

        //執(zhí)行下一個處理器
        returnsuper.next(param);
    }
}

客戶端:執(zhí)行處理器鏈路

HandlerClient客戶端類負(fù)責(zé)發(fā)起整個處理器鏈路的執(zhí)行,通過executeChain()方法。如果處理器鏈路返回錯誤信息,即校驗(yàn)未通過,則整個鏈路截斷(停止),返回相應(yīng)的錯誤信息。

public class HandlerClient {

  public static Result executeChain(AbstractCheckHandler handler, ProductVO param) {
      //執(zhí)行處理器
      Result handlerResult = handler.handle(param);
      if (!handlerResult.isSuccess()) {
          System.out.println("HandlerClient 責(zé)任鏈執(zhí)行失敗返回:" + handlerResult.toString());
          return handlerResult;
      }
      return Result.success();
  }
}

以上,責(zé)任鏈模式相關(guān)的類已經(jīng)創(chuàng)建好了。接下來就可以創(chuàng)建商品了。

創(chuàng)建商品:抽象步驟,化繁為簡

createProduct()創(chuàng)建商品方法抽象為2個步驟:①參數(shù)校驗(yàn)、②創(chuàng)建商品。參數(shù)校驗(yàn)使用責(zé)任鏈模式進(jìn)行校驗(yàn),包含:空值校驗(yàn)、價格校驗(yàn)、庫存校驗(yàn)等等,只有鏈上的所有處理器均校驗(yàn)通過,才調(diào)用saveProduct()創(chuàng)建商品方法;否則返回校驗(yàn)錯誤信息。

createProduct()創(chuàng)建商品方法中,通過責(zé)任鏈模式,我們將校驗(yàn)邏輯進(jìn)行解耦。createProduct()創(chuàng)建商品方法中不需要關(guān)注都要經(jīng)過哪些校驗(yàn)處理器,以及校驗(yàn)處理器的細(xì)節(jié)。

/**
 * 創(chuàng)建商品
 * @return
 */
@Test
public Result createProduct(ProductVO param) {

    //參數(shù)校驗(yàn),使用責(zé)任鏈模式
    Result paramCheckResult = this.paramCheck(param);
    if (!paramCheckResult.isSuccess()) {
        return paramCheckResult;
    }

    //創(chuàng)建商品
    return this.saveProduct(param);
}

參數(shù)校驗(yàn):責(zé)任鏈模式

參數(shù)校驗(yàn)paramCheck()方法使用責(zé)任鏈模式進(jìn)行參數(shù)校驗(yàn),方法內(nèi)沒有聲明具體都有哪些校驗(yàn),具體有哪些參數(shù)校驗(yàn)邏輯是通過多個處理器鏈傳遞的。如下:

/**
 * 參數(shù)校驗(yàn):責(zé)任鏈模式
 * @param param
 * @return
 */
private Result paramCheck(ProductVO param) {

    //獲取處理器配置:通常配置使用統(tǒng)一配置中心存儲,支持動態(tài)變更
    ProductCheckHandlerConfig handlerConfig = this.getHandlerConfigFile();

    //獲取處理器
    AbstractCheckHandler handler = this.getHandler(handlerConfig);

    //責(zé)任鏈:執(zhí)行處理器鏈路
    Result executeChainResult = HandlerClient.executeChain(handler, param);
    if (!executeChainResult.isSuccess()) {
        System.out.println("創(chuàng)建商品 失敗...");
        return executeChainResult;
    }

    //處理器鏈路全部成功
    return Result.success();
}

paramCheck()方法步驟說明如下:

?? 步驟1:獲取處理器配置。

通過getHandlerConfigFile()方法獲取處理器配置類對象,配置類保存了鏈上各個處理器的上下級節(jié)點(diǎn)配置,支持流程編排、動態(tài)擴(kuò)展。通常配置是通過Ducc(京東自研的配置中心)、Nacos(阿里開源的配置中心)等配置中心存儲的,支持動態(tài)變更、實(shí)時生效。

基于此,我們便可以實(shí)現(xiàn)校驗(yàn)處理器的編排、以及動態(tài)擴(kuò)展了。我這里沒有使用配置中心存儲處理器鏈路的配置,而是使用JSON串的形式去模擬配置,大家感興趣的可以自行實(shí)現(xiàn)。

/**
 * 獲取處理器配置:通常配置使用統(tǒng)一配置中心存儲,支持動態(tài)變更
 * @return
 */
private ProductCheckHandlerConfig getHandlerConfigFile() {
    //配置中心存儲的配置
    String configJson = "{\"handler\":\"nullValueCheckHandler\",\"down\":true,\"next\":{\"handler\":\"priceCheckHandler\",\"next\":{\"handler\":\"stockCheckHandler\",\"next\":null}}}";
    //轉(zhuǎn)成Config對象
    ProductCheckHandlerConfig handlerConfig = JSON.parseObject(configJson, ProductCheckHandlerConfig.class);
    return handlerConfig;
}

ConfigJson存儲的處理器鏈路配置JSON串,在代碼中可能不便于觀看,我們可以使用json.cn等格式化看一下,如下,配置的整個調(diào)用鏈路規(guī)則特別清晰。

圖片圖片

getHandlerConfigFile()類獲到配置類的結(jié)構(gòu)如下,可以看到,就是把在配置中心儲存的配置規(guī)則,轉(zhuǎn)換成配置類ProductCheckHandlerConfig對象,用于程序處理。

注意,此時配置類中存儲的僅僅是處理器Spring Bean的name而已,并非實(shí)際處理器對象。

圖片圖片

接下來,通過配置類獲取實(shí)際要執(zhí)行的處理器。

?? 步驟2:根據(jù)配置獲取處理器。

上面步驟1通過getHandlerConfigFile()方法獲取到處理器鏈路配置規(guī)則后,再調(diào)用getHandler()獲取處理器。

getHandler()參數(shù)是如上ConfigJson配置的規(guī)則,即步驟1轉(zhuǎn)換成的ProductCheckHandlerConfig對象;根據(jù)ProductCheckHandlerConfig配置規(guī)則轉(zhuǎn)換成處理器鏈路對象。代碼如下:

* 使用Spring注入:所有繼承了AbstractCheckHandler抽象類的Spring Bean都會注入進(jìn)來。Map的Key對應(yīng)Bean的name,Value是name對應(yīng)相應(yīng)的Bean
 */
@Resource
private Map<String, AbstractCheckHandler> handlerMap;

/**
 * 獲取處理器
 * @param config
 * @return
 */
private AbstractCheckHandler getHandler (ProductCheckHandlerConfig config) {
    //配置檢查:沒有配置處理器鏈路,則不執(zhí)行校驗(yàn)邏輯
    if (Objects.isNull(config)) {
        returnnull;
    }
    //配置錯誤
    String handler = config.getHandler();
    if (StringUtils.isBlank(handler)) {
        returnnull;
    }
    //配置了不存在的處理器
    AbstractCheckHandler abstractCheckHandler = handlerMap.get(config.getHandler());
    if (Objects.isNull(abstractCheckHandler)) {
        returnnull;
    }
    
    //處理器設(shè)置配置Config
    abstractCheckHandler.setConfig(config);
    
    //遞歸設(shè)置鏈路處理器
    abstractCheckHandler.setNextHandler(this.getHandler(config.getNext()));

    return abstractCheckHandler;
}

?? ?? 步驟2-1:配置檢查。

代碼14~27行,進(jìn)行了配置的一些檢查操作。如果配置錯誤,則獲取不到對應(yīng)的處理器。代碼23行handlerMap.get(config.getHandler())是從所有處理器映射Map中獲取到對應(yīng)的處理器Spring Bean。

注意第5行代碼,handlerMap存儲了所有的處理器映射,是通過Spring @Resource注解注入進(jìn)來的。注入的規(guī)則是:所有繼承了AbstractCheckHandler抽象類(它是Spring管理的Bean)的子類(子類也是Spring管理的Bean)都會注入進(jìn)來。

注入進(jìn)來的handlerMap中 Map的Key對應(yīng)Bean的name,Value是name對應(yīng)的Bean實(shí)例,也就是實(shí)際的處理器,這里指空值校驗(yàn)處理器、價格校驗(yàn)處理器、庫存校驗(yàn)處理器。如下:

圖片圖片

這樣根據(jù)配置ConfigJson(?? 步驟1:獲取處理器配置)中handler:"priceCheckHandler"的配置,使用handlerMap.get(config.getHandler())便可以獲取到對應(yīng)的處理器Spring Bean對象了。

?? ?? 步驟2-2:保存處理器規(guī)則。

代碼29行,將配置規(guī)則保存到對應(yīng)的處理器中abstractCheckHandler.setConfig(config),子類處理器就持有了配置的規(guī)則。

?? ?? 步驟2-3:遞歸設(shè)置處理器鏈路。

代碼32行,遞歸設(shè)置鏈路上的處理器。

//遞歸設(shè)置鏈路處理器 abstractCheckHandler.setNextHandler(this.getHandler(config.getNext()));

這一步可能不太好理解,結(jié)合ConfigJson配置的規(guī)則來看,似乎就很很容易理解了。

圖片圖片

由上而下,NullValueCheckHandler 空值校驗(yàn)處理器通過setNextHandler()方法設(shè)置自己持有的下一節(jié)點(diǎn)的處理器,也就是價格處理器PriceCheckHandler。

接著,PriceCheckHandler價格處理器,同樣需要經(jīng)過步驟2-1配置檢查、步驟2-2保存配置規(guī)則,并且最重要的是,它也需要設(shè)置下一節(jié)點(diǎn)的處理器StockCheckHandler庫存校驗(yàn)處理器。

StockCheckHandler庫存校驗(yàn)處理器也一樣,同樣需要經(jīng)過步驟2-1配置檢查、步驟2-2保存配置規(guī)則,但請注意StockCheckHandler的配置,它的next規(guī)則配置了null,這表示它下面沒有任何處理器要執(zhí)行了,它就是整個鏈路上的最后一個處理節(jié)點(diǎn)。

通過遞歸調(diào)用getHandler()獲取處理器方法,就將整個處理器鏈路對象串聯(lián)起來了。如下:

圖片圖片

友情提示:遞歸雖香,但使用遞歸一定要注意截斷遞歸的條件處理,否則可能造成死循環(huán)哦!

實(shí)際上,getHandler()獲取處理器對象的代碼就是把在配置中心配置的規(guī)則ConfigJson,轉(zhuǎn)換成配置類ProductCheckHandlerConfig對象,再根據(jù)配置類對象,轉(zhuǎn)換成實(shí)際的處理器對象,這個處理器對象持有整個鏈路的調(diào)用順序。

?? 步驟3:客戶端執(zhí)行調(diào)用鏈路。

public class HandlerClient {

  public static Result executeChain(AbstractCheckHandler handler, ProductVO param) {
      //執(zhí)行處理器
      Result handlerResult = handler.handle(param);
      if (!handlerResult.isSuccess()) {
          System.out.println("HandlerClient 責(zé)任鏈執(zhí)行失敗返回:" + handlerResult.toString());
          return handlerResult;
      }
      return Result.success();
  }
}

getHandler()獲取完處理器后,整個調(diào)用鏈路的執(zhí)行順序也就確定了,此時,客戶端該干活了!

HandlerClient.executeChain(handler, param)方法是HandlerClient客戶端類執(zhí)行處理器整個調(diào)用鏈路的,并接收處理器鏈路的返回值。

executeChain()通過AbstractCheckHandler.handle()觸發(fā)整個鏈路處理器順序執(zhí)行,如果某個處理器校驗(yàn)沒有通過!handlerResult.isSuccess(),則返回錯誤信息;所有處理器都校驗(yàn)通過,則返回正確信息Result.success()。

總結(jié):串聯(lián)方法調(diào)用流程

基于以上,再通過流程圖來回顧一下整個調(diào)用流程。

圖片圖片

測試:代碼執(zhí)行結(jié)果

場景1:創(chuàng)建商品參數(shù)中有空值(如下skuId參數(shù)為null),鏈路被空值處理器截斷,返回錯誤信息

//創(chuàng)建商品參數(shù)
ProductVO param = ProductVO.builder()
      .skuId(null).skuName("華為手機(jī)").Path("http://...")
      .price(new BigDecimal(1))
      .stock(1)
      .build();

測試結(jié)果

圖片圖片

場景2:創(chuàng)建商品價格參數(shù)異常(如下price參數(shù)),被價格處理器截斷,返回錯誤信息

ProductVO param = ProductVO.builder()
      .skuId(1L).skuName("華為手機(jī)").Path("http://...")
      .price(new BigDecimal(-999))
      .stock(1)
      .build();

測試結(jié)果

圖片圖片

場景 3:創(chuàng)建商品庫存參數(shù)異常(如下stock參數(shù)),被庫存處理器截斷,返回錯誤信息。

//創(chuàng)建商品參數(shù),模擬用戶傳入
ProductVO param = ProductVO.builder()
      .skuId(1L).skuName("華為手機(jī)").Path("http://...")
      .price(new BigDecimal(1))
      .stock(-999)
      .build();

測試結(jié)果

圖片圖片

場景4:創(chuàng)建商品所有處理器校驗(yàn)通過,保存商品。

![15](C:\Users\18796\Desktop\文章\15.png)![15](C:\Users\18796\Desktop\文章\15.png)![15](C:\Users\18796\Desktop\文章\15.png)![15](C:\Users\18796\Desktop\文章\15.png)//創(chuàng)建商品參數(shù),模擬用戶傳入
ProductVO param = ProductVO.builder()
      .skuId(1L).skuName("華為手機(jī)").Path("http://...")
      .price(new BigDecimal(999))
      .stock(1).build();

測試結(jié)果

圖片

案例二:工作流,費(fèi)用報銷審核流程

同事小賈最近剛出差回來,她迫不及待的就提交了費(fèi)用報銷的流程。根據(jù)金額不同,分為以下幾種審核流程。報銷金額低于1000元,三級部門管理者審批即可,1000到5000元除了三級部門管理者審批,還需要二級部門管理者審批,而5000到10000元還需要一級部門管理者審批。即有以下幾種情況:

  1. 小賈需報銷500元,三級部門管理者審批即可。
  2. 小賈需報銷2500元,三級部門管理者審批通過后,還需要二級部門管理者審批,二級部門管理者審批通過后,才完成報銷審批流程。
  3. 小賈需報銷7500元,三級管理者審批通過后,并且二級管理者審批通過后,流程流轉(zhuǎn)到一級部門管理者進(jìn)行審批,一級管理者審批通過后,即完成了報銷流程。

UML圖UML圖

AbstractFlowHandler作為處理器抽象類,抽象了approve()審核方法,一級、二級、三級部門管理者處理器繼承了抽象類,并重寫其approve()審核方法,從而實(shí)現(xiàn)特有的審核邏輯。

圖片圖片

配置類如下所示,每層的處理器都要配置審核人、價格審核規(guī)則(審核的最大、最小金額)、下一級處理人。配置規(guī)則是可以動態(tài)變更的,如果三級部門管理者可以審核的金額增加到2000元,修改一下配置即可動態(tài)生效。

圖片圖片

代碼實(shí)現(xiàn)與案例一相似,感興趣的自己動動小手吧~

責(zé)任鏈的優(yōu)缺點(diǎn)

圖片圖片

圖片

責(zé)任編輯:武曉燕 來源: JAVA日知錄
相關(guān)推薦

2021-04-20 10:50:38

Spring Boot代碼Java

2023-03-28 08:07:12

2025-08-04 01:00:00

責(zé)任鏈模式權(quán)限

2017-06-26 09:40:50

Python代碼寫法

2017-07-07 16:57:35

代碼Python

2025-09-22 09:31:34

2010-05-28 15:16:33

SharePoint 工作流

2021-03-29 11:20:39

前端代碼工作流

2020-10-25 19:58:04

Pythonic代碼語言

2022-10-26 08:00:43

Activiti工作流BPM

2021-10-14 11:34:05

技術(shù)工作流引擎

2013-04-23 10:28:08

IBeamMDAAWF

2024-04-25 08:00:00

DevOps架構(gòu)軟件開發(fā)

2022-07-29 08:40:20

設(shè)計模式責(zé)任鏈場景

2015-07-14 09:26:28

微型工作流引擎設(shè)計

2021-04-27 22:38:41

代碼開發(fā)前端

2014-02-28 13:46:35

Angular代碼

2023-08-01 08:54:02

接口冪等網(wǎng)絡(luò)

2021-10-17 22:23:43

5G4G數(shù)據(jù)

2010-01-04 17:42:50

SilverLight
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號