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

子月生發表於2021-03-03

關於業務通用框架的思考

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

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 還有很多需要改進的地方。

最後,感謝閱讀。

參考資料

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

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

相關文章