定義
管道模式使用有序的Stage(或者Handler)來順序的處理一個輸入值词顾,每個處理過程被看做一個階段洽故。 但是每一個階段都以來上一個階段的輸出。
如果不依賴上一個階段的輸出結(jié)果,那么使用責任鏈模式即可广恢。責任鏈模式的每個處理器互相獨立欣孤,不依賴別的處理器結(jié)構(gòu)馋没。
做個比喻:
管道模式可用看做是富士康流水線,每個環(huán)節(jié)都依賴上個環(huán)節(jié)的輸出
責任鏈模式類似于招標降传,下發(fā)任務篷朵,誰有能力誰處理,不需要關(guān)心其他人婆排;
當然設(shè)計模式肯定是可以混用的声旺,都是使用兩個模式也是OK的。
需求中的案例
在負責的項目中段只,一般我們的業(yè)務模型會越來越復雜腮猖,想要做一件事需要和多個模型交互;
而模型之間又存在依賴關(guān)系赞枕,一個模型依賴另外一個模型的某個屬性澈缺;
每個模型都有需要校驗的部分,連續(xù)多個之后炕婶,我們的代碼結(jié)構(gòu)就會變得比較長姐赡。
比如:
輸入某個任務:
1、檢查任務是否有其他導出渠道柠掂。 查出渠道模型雏吭;
2、檢查渠道是否審核通過陪踩;
3杖们、檢查渠道審核通過之后是否有導出記錄; 查記錄模型肩狂;
4摘完、檢查導出記錄狀態(tài)是否符合預期;
復制代碼
3,4是以來1傻谁,2的結(jié)果的孝治,但是都在一起寫,目前還不是很長,但是如果繼續(xù)增加邏輯就會變得更長谈飒。
如果使用的管道模式的話:
Code
定義階段
管道模式的輸入依賴上一個階段的輸出岂座,因此入?yún)⒑统鰠⒍夹枰紤]進去。
public interface PipeStage<I,O> {
/**
* 通過異常來終止觀點的執(zhí)行過程
*/
class StepException extends RuntimeException {
public StepException(Throwable t) {
super(t);
}
}
O process(I input);
}
復制代碼
定義管道
管道可以不斷的添加新的階段杭措,并且每個階段依賴上個階段的輸出
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class Pipeline<I, O> {
private final PipeStage<I, O> currentHandler;
Pipeline(PipeStage<I, O> currentHandler) {
this.currentHandler = currentHandler;
}
<K> Pipeline<I, K> addHandler(PipeStage<O, K> newHandler) {
log.info("addHandler");
PipeStage<I, K> ikHandler = input -> newHandler.process(currentHandler.process(input));
return new Pipeline<>(ikHandler);
}
O execute(I input) {
return currentHandler.process(input);
}
}
復制代碼
定義管道階段實現(xiàn)
使用剛才的例子:
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class AbstractHandler {
@Data
static class ChannelConfig {
/**
* 渠道Id
*/
private String id;
/***
* 審判狀態(tài)
*/
private int applyStatus;
}
@Data
static class ChannelExportRecord{
private String configId;
/**
* 導出狀態(tài)
*/
private int exportStatus;
}
static class CheckApprovedHandler implements PipeStage<String, ChannelConfig> {
@Override
public ChannelConfig process(String input) {
// ... 此處查詢input中的值费什,判斷渠道配置
log.info("apprvoed {}",input);
ChannelConfig channelConfig = new ChannelConfig();
return channelConfig;
}
}
public static class CheckRecordSuccessHandler implements PipeStage<ChannelConfig, ChannelExportRecord> {
@Override
public ChannelExportRecord process(ChannelConfig input) {
log.info("record passed {}",input);
return new ChannelExportRecord();
}
}
}
復制代碼
使用管道
把我們剛才的代碼組合起來:
Slf4j
public class PipeDemo {
public static void main(String[] args) {
Pipeline<String, ChannelExportRecord> handler = new Pipeline<>(
new CheckApprovedHandler())
.addHandler(new CheckRecordSuccessHandler());
//String filters = (String)handler;
log.info("start Handler");
ChannelExportRecord record = handler.execute("導出配置Id");
log.info("result {}", JSON.toJSONString(record));
}
}
復制代碼
運行結(jié)果
總結(jié)
1、每個管道階段在實現(xiàn)的時候是互相獨立的手素;這樣也更方便單測 2鸳址、管道階段在使用的時候會組合成一個流水線管道,每個階段的輸入和輸出有一定依賴關(guān)系泉懦,上個階段要為下個階段準備好數(shù)據(jù)稿黍。 3、設(shè)計模式的通用好處:代碼可讀性崩哩,維護性提升巡球;當然管道模式有點像Java的Stream,只是Stream里面一般不會寫筆記復雜的邏輯邓嘹。