entitybuilder–一個簡單的業務通用框架

關於業務通用框架的思考

業務系統是千差萬別的,例如,保存、更新和刪除訂單,或者保存訂單和保存客戶,走的根本不是一個流程。但是,它們還是有共同點,它們的流程大致可以分成下面的幾個部分:

zzs_entitybuilder_01

  1. 拿到增刪改等操作所需的基礎數據;
  2. 初始化基礎數據;
  3. 對基礎數據進行校驗;
  4. 利用基礎數據,構建出要進行增刪改等操作的對象;
  5. 持久化或其他操作。

基於這一點,我試著抽取出一套適用於不同業務、不同用例、不同場景的通用業務框架。剛好,去年部門開始重構訂單系統,我試著將自己的想法付諸行動。經過幾次調整後,總算形成了一個簡單的業務通用框架–entitybuilder。

當然,我更多想表達的,是一種思想、一種規範,而非工具本身。如果真要說是框架,entitybuilder 就太簡陋了。

entitybuilder 的結構

entitybuilder 包含三個主要部分,基礎數據 base data、構建器 entity builder 和結果對象 result entity。我拿到了 base data,把它丟進 entity builder,entity builder 就會幫我構建出 result entity,拿到 result entity 後,我要持久化也行,直接返回給更上層調用者也行。

entity builder 構建 result entity 的過程被定義為:初始化->校驗->構建。

zzs_entitybuilder_02

entitybuilder1.0–規範流程

基於上面的模型,也就有了 entitybuilder1.0,它的結構如下。

對調用者來說,只需要設置好基礎數據,調用build方法就能完成初始化、校驗、構建,當然,EntityBuilder還支援僅作為校驗器使用,因為有時我們並不需要結果對象,只需要校驗基礎數據就行。

對實現者來說,用戶需要繼承AbstractEntityBuilder,並實現初始化、校驗和構建方法。

zzs_entitybuilder_03

以訂單保存為例,下面展示如何使用 entitybuilder。程式碼的調用非常簡單,這裡需要注意,EntityBuilder對象必須是多例的。

    public String save(DefaultOrderSaveCmd cmd) {
        // 獲取構建器(多例的)
        EntityBuilder<BaseOrderSaveCmd, OrderSaveE> entityBuilder = getSaveEntityBuilder();

        // 設置基礎數據
        entityBuilder.setBaseData(cmd);
        
        // 構建保存實體
        OrderSaveE entity = entityBuilder.build();
        
        // 持久化操作
        orderDao.save(entity);
        
        return entity.getId();
    }

entitybuilder2.0–多場景支援

entitybuilder1.0 只是規範了業務流程,在多場景方面還是存在問題。

一個業務用例可能會有不同的場景,例如,客戶保存可能就不只一個入口,按照 entitybuilder1.0 的設計,我們需要將所有場景的邏輯都堆積到構建器中。顯然,這是不合理的。

參考 spring 的 postprocessor,我在構建器中引入了校驗器和處理器的支援。構建器中定義了用例的主流程,不同場景可以通過註冊校驗器和處理器來對主流程進行修飾。在 entitybuilder1.0 的基礎上修改,得到以下結構:

zzs_entitybuilder_05

和 entitybuilder 1.0 相比,對調用者來說,可以通過註冊驗器和處理器來影響構建器的主流程,對構建器實現者來說,改為繼承AbstractFlexibleEntityBuilder

那麼校驗器和處理器如何影響主流程呢?下面通過一張圖來說明。在 entitybuilder1.0 中,調用者無需知道構建器中的邏輯,現在卻需要知道(有好有壞吧)。

zzs_entitybuilder_04

以訂單保存為例,程式碼示例如下。

    public String save(DefaultOrderSaveCmd cmd) {
        // 獲取構建器
        AbstractFlexibleEntityBuilder<BaseOrderSaveCmd, OrderSaveE> entityBuilder = getSaveEntityBuilder();
        
        // 設置基礎數據
        entityBuilder.setBaseData(cmd);
        
        // 對構建器進行部分更改,例如註冊處理器或檢驗器
        entityBuilder.registerValidator(myOrderSaveValidator);
        entityBuilder.registerEntityBuilderPostProcessor(myOrderSavePostProcessor);
        
        // 構建保存實體
        OrderSaveE entity = entityBuilder.build();
        
        // 持久化操作
        orderDao.save(entity);
        
        return entity.getId();
    }

基礎數據的組成

entitybuilder 的可用性極大依賴於基礎數據的規範。在 entitybuilder 中,基礎數據的成員屬性應該包含兩個部分:主體屬性和關聯對象。例如,訂單的基礎數據就包括了訂單本身以及它的關聯對象,如客戶、操作人等。

zzs_entitybuilder_06

為什麼要包含這兩個部分呢?

構建器中包含了業務的大部分邏輯,我們需要調用各種通用方法,這些方法的入參對象無非就是主體屬性或關聯對象屬性。基礎數據對象將在 EntityBuilder 的整個生命周期中傳遞,通過它來傳遞關聯對象,可以保證關聯對象只需要初始化一次,從而減少重複 IO。

如果一開始放入構建器的基礎數據對象中已經有關聯對象了,那麼,構建器也不會再去初始化它。這一點在批量構建時將非常有用。

事務控制

在 entitybuilder 的規範中,結果對象的持久化是在一個事務/方法中完成主體對象和關聯對象的持久化,但是,在某個場景下,我們需要在事務中進行某些自定義操作,例如,訂單保存完成後,向某個外部系統推送數據,推送失敗,事務跟著回滾。

針對這種場景,也是可以支援的。事務中的自定義操作將作為函數的形式傳遞,在基礎數據中設置好,持久化時就會執行它。

    @Override
    public String save(DefaultOrderSaveCmd cmd) {
        // 獲取構建器
        AbstractFlexibleEntityBuilder<BaseOrderSaveCmd, OrderSaveE> entityBuilder = getSaveEntityBuilder();
        
        // 設置基礎數據
        entityBuilder.setBaseData(cmd);
        
        // 對基礎數據進行部分更改,例如設置保存事務中需要進行的操作
        cmd.addSaveConsumer(order -> {
            // 有的自定義操作需要放入保存事務,如果失敗,訂單數據也會回滾
            // 省略程式碼······
        });

        // 構建保存實體
        OrderSaveE entity = entityBuilder.build();
        
        // 持久化操作
        orderDao.save(entity);
        
        return entity.getId();
    }
    // @Transactional
    public String save(OrderSaveE entity) {
        // 保存訂單
        // 省略程式碼······
        
        // 保存產品
        // 省略程式碼······
        
        
        // 保存附件
        // 省略程式碼······
        
        
        // 執行保存事務中的函數
        entity.getSaveConsumers().forEach(x -> x.accept(entity));
        
        return entity.getId();
    }

以上基本介紹完 entitybuilder。這裡還是強調一點,我更多的是想表達一種思想、一種規範,因為作為工具,entitybuilder 還有很多需要改進的地方。

最後,感謝閱讀。

參考資料

相關源碼請移步://github.com/ZhangZiSheng001/zzs-code-thought/01-entitybuilder-demo

本文為原創文章,轉載請附上原文出處鏈接://www.cnblogs.com/ZhangZiSheng001/p/14472782.html