Clean Architecture 實作篇 (六)

儲存層轉接器實作

elliot
Feb 11, 2024

應用程式服務呼叫 轉接埠介面,而 轉接埠介面 由 儲存層轉接器 實作
這麼做的用途是為了解決高層級依賴低層級的細節,意思是說在 應用程式服務 和 儲存程式碼之間建立起一層屏障,可以保護 Domain 不仰賴外部儲存層,達到更好去更換 DB、或是儲存方式。

一個儲存層轉接器的職責

獲取輸入-> 將輸入轉換成對應資料庫格式 -> 將輸入資料傳遞給資料庫 -> 把資料庫的輸出轉換成應用程式 -> 回傳輸出資料。

最常見的就是 傳入 ORM, ORM 轉換成 資料庫格式 -> 傳遞給資料庫儲存後回傳 -> 當 DB 結果轉換成 ORM,傳回該 ORM

而其中最需要釐清的觀念是,傳遞給儲存層轉接器 的 輸入模型(Input Model) 和 輸出模型(Output Model) 是 歸屬在應用程式層的而非儲存層轉接器,原因是我們應該實際去思考 Domain 領域內的模型才是最重要的,儲存層應該要配合其異動而做修改,而不是當 DB 結構異動時去調整 Domain 領域內的模型。

而對於分割 應用程式核心 可用的資料庫作業的轉接埠介面

可以分成 單一集中式的輸出轉接埠

導致不必要的麻煩,和難以測試

和 透過介面隔離原則 (ISP) ,將單一過廣的介面拆分為多個,且用戶端只使用最低限度所需的方法。

不過實際上還是得看你的需求,有得時候你就想表達一組內聚力強、高度關係的資料庫作業。

接續上面,接著要來看的是 儲存層轉接器

以 DDD 為例,會更推薦我們 以 “聚合” 為單位,來切割出不同的儲存層轉接器,這樣使得程式碼更加清晰易懂。
而不同的 Bounded Context 會有各自的儲存需求,就需要各自的建立儲存轉接器(一個或多個)。而不同 Bounded Context 之間是不能直接存取的,是必須透過 對方的輸入轉接埠 獲取才行。

那我們到底該不該直接把領域內的實體,直接存入資料庫呢?

答案是 不行。 建議還是需要先轉換一層轉換(DTO),原因是直接將領域模型傳給了儲存轉接器,那就代表把細節也暴露出去了,導致資料庫的資料對於 領域模型有深深的耦合關係;換句話說,當我資料庫讀取的資料,如果沒有夠過轉換層的轉換關係,是不是就代表 領域模型 是 對於資料庫是直接的耦合

那 database transaction 到底該歸在哪呢?

答案是 應用服務。原因是 對於儲存層轉接器來說,根本不會知道 它和哪些作業是在同一個使用案例底下的,意思是說儲存層就只有負責儲存 根本看不出 Context,自然而然也就不知道該 Rollback 哪些東西 該 Commit 哪些東西。

--

--