實戰項目:設計實現一個流程編排框架(實現)

上兩篇文章主要講了《[實戰項目:設計實現一個流程編排框架(分析)(https://mp.weixin.qq.com/s/veLQZJqYNKbYvuCi7Pf_nA)]》《實戰項目:設計實現一個流程編排框架(設計》我們介紹瞭如何通過合理的分析,來實現需求的同時滿足易用、易擴展、靈活、低延遲、高容錯等非功能性需求。

針對編排框架的開發如何做高質量的代碼實現。說的具體點就是,如何利用設計思想、原則、模式、編碼規範、重構技巧等,寫出易讀、易擴展、易維護、靈活、簡潔、可複用、易測試的代碼。

流程註冊

之前有講到要支持yml、properties、xml、json、接口的形式註冊流程模型,爲了體現職責單一原則,我們需要把一種格式解析的邏輯獨立處理,爲了體現對擴展開發,對修改關閉原則,我們先定義一組接口,然後通過工廠模式提供對應的實現邏輯;這裏工廠是使用者,通過接口調用具體的實現,實現在這裏是提供者,又是一組策略模式

流程加載

流程加載我們需要知道其他的幾個需求功能點:1、提供對外統一訪問接口;2、提供執行記錄和執行耗時;3、不同流程節點需要定義不同的解析器;4、通過工廠創建解析類型;5、流程節點按照順序執行。

通過不同的節點類型執行不同的解析方式,顯而易見這裏需要用工廠模式去做解析類創建,而且需要做到對外擴展開發對修改關閉,新增節點不用動其他代碼邏輯,只要在工廠函數裏面添加一個節點解析器;同時我們這裏定義一個Map集合用於在加載工廠函數的時候就把解析對象創建,而不用每次解析的時候再去創建解析器,減少不必要的內存

代碼如下:

public class NodeComponentFactory {

    private final static Map<String,NodeParser> cacheParser = new HashMap<>();

    static {
        cacheParser.put(NodeParserEnum.method.name(),new MethodNodeComponent());
        cacheParser.put(NodeParserEnum.bean.name(),new BeanNodeComponent());
        cacheParser.put(NodeParserEnum.condition.name(),new ConditionNodeComponent());
        cacheParser.put(NodeParserEnum.service.name(),new ServiceNodeComponent());
        cacheParser.put(NodeParserEnum.subflow.name(),new SubFlowNodeComponent());
    }

    public static NodeParser getNodeInstance(String nodeName){
        return cacheParser.get(nodeName);
    }
}

當我們發現每一種節點解析類型都需要去實現parser接口,而且每個節點都有類似的步驟,那我們這裏就要考慮用抽象工廠,也符合一個依賴倒置的的設計原則,上層模塊通過依賴接口訪問,下次模塊繼承抽象類,同時也用到了策略模式做接口調用;在實現的邏輯過程我們會發現很多步驟是重複的,比如初始化入參、執行記錄,所有我們把重複的內容放到抽象類,通過模板模式的方式,讓流程節點只關注解析層面;

public abstract class AbstractNodeComponent implements NodeParser{

    public Map<String, Node> nodeMap;


    /**
     * 初始化參數
     * @param inputUrl
     * @param baseInput
     * @return
     */
    public BaseInput initInput(String inputUrl, BaseInput baseInput){
        BaseInput baseInputTarget = ClassUtil.newInstance(inputUrl, BaseInput.class);
        BeanUtils.copyProperties(baseInput,baseInputTarget);
        return baseInputTarget;
    }


    /**
     * 解析節點信息
     * @param node 節點信息
     * @param baseInput 請求參數
     * @param baseTemp 臨時上下文
     * @return
     */
    public BaseOutput parserNode(Node node, BaseInput baseInput, BaseTemp baseTemp){
        baseTemp.setFlowRecord(baseTemp.getFlowRecord().append(FlowConstants.NODEKEY+FlowConstants.NODE+FlowConstants.COLON+node.getId()));
        BaseOutput baseOutput = parser(node, baseInput, baseTemp);
        return baseOutput;
    };

    @Override
    public void setNodeMap(Map<String, Node> nodeMap) {
        this.nodeMap = nodeMap;
    }

    @Override
    public abstract BaseOutput parser(Node node, BaseInput baseInput, BaseTemp baseTemp);

}

流程加載順序

流程執行我們需要把組件分的很細,最好是獨立實現一個功能的類劃分成一個組件,體現職責單一原則,也只要把執行功能劃分的很細,才能在流程執行的各個流程中靈活組合;在下面流程圖中可以看到幾個組件,第一個是流程統一執行的入口,這裏會有兩個地方會用到,第一個就是給外部調用的接口,第二個是子流程執行的入口;第二個組件是節點統一加載管理組件也就是上文提到的工廠類;第三個就是每個組件自己的解析器,用於實現不同類型節點的操作;在設計的過程中一定知道 流程 、管理、節點之間的邊界,減少耦合,只有這樣不同的組件才能靈活組成。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章