六邊形架構(端口與適配器)


      在六邊形架構中,提出了一種具有對稱性特征的架構風格。在這種架構中,不同的客戶通過“平等”的方式與系統交互。需要新的客戶嗎?不是問題。只需要添加一個新的適配器將客戶輸入轉化成能被系統API所理解的參數就行了。同時,系統輸出,比如圖形界面、持久化和消息等都可以通過不同方式實現,並且是可互換的。這是可能的,因為對於每種特定的輸出,都有一個新建的適配器負責完成相應的轉化功能。

      至此,我們有充足的理由認為,這將是一種具有持久生命力的架構。

      現在,很多聲稱使用分層架構的團隊實際上使用的就是六邊形架構。這是因為很多項目都使用了某種形式的依賴注入。並不是說依賴注入天生就是六邊形架構,而是說使用依賴注入的架構自然地具有了端口和適配器風格。我們將對此做詳盡的解釋。

      我們通常將客戶與系統交互的地方稱為“前端”;同樣,我們將系統中獲取、存儲持久化數據和發送輸出數據的地方稱為“后端”。但是,六邊形架構提倡用一種新的視角來看待整個系統。該架構中存在兩個區域,分別是“外部區域”和“內部區域”。在外部區域中,不同的客戶均可以提交輸入;而內部的系統則用於獲取持久化數據,並對程序輸出進行存儲(比如數據庫),或者在中途將輸出轉發到另外的地方(比如消息,轉發到消息隊列)。

      每種類型的客戶都有自己的適配器,該適配器用於將客戶輸入轉化為程序內部API所理解的輸入。六邊形每條不同的邊代表了不同種類型的端口,端口要么處理輸入,要么處理輸出。圖中有3個客戶請求均抵達相同的輸入端口(適配器A、B和C),另一個客戶請求使用了適配器D。可能前3個請求使用了HTTP協議(瀏覽器、REST和SOAP等),而后一個請求使用了MSMQ的協議。端口並沒有明確的定義,它是一個非常靈活的概念。無論采用哪種方式對端口進行划分,當客戶請求到達時,都應該有相應的適配器對輸入進行轉化,然后適配器將調用應用程序的某個操作或者向應用程序發送一個事件,控制權由此交給內部區域。

      我們不必自己實現端口

      通常來說,我們都不用自己實現端口。我們可以將端口想成是HTTP,而將適配器想成是.NET的HTTP請求處理管道。或者,我們可以為MSMQ創建消息監聽器,在這種情況下,端口是消息機制,而適配器則是消息監聽器,因為消息監聽器將負責從消息中提取數據,並將數據轉化為應用層API(領域模型的直接客戶)所能理解的參數。

      按照功能需求來設計內部區域中的應用程序

      在使用六邊形架構時,我們應該根據用例來設計應用程序,而不是根據需要支持的客戶數目業設計。任何客戶都可能向不同的端口發出請求,但是所有的適配器都將使用相同的API。

      應用程序通過公共API接收客戶請求。應用程序邊界,即內部六邊形,也是用例(或用戶故事)邊界。換句話說,我們應該根據應用程序的功能需求來創建用例,而不是客戶數量或輸出機制。當應用程序通過API接收到請求時,它將使用領域模型來處理請求,其中便包括對業務邏輯的執行。因此,應用層API通過應用服務的方式展現給外部。再次提醒大家,這里的應用服務是領域模型的直接客戶,就像在分層架構中一樣。

      以下代碼表示通過WebAPI發布的RESTful資源。當請求到達HTTP的輸入端口時,相應的適配器將對請求的處理委派給應用服務:

public class ProductControl
{
      private ProductService productService; [HttpGet] public HttpResponseMessage GetProduct(string tenantId, string productId) { HttpResponseMessage rm; Product product = productService.Product(tenantId, productId); if(product == null) { rm = Request.CreateResponse(HttpStatusCode.NotFound); } else { rm = Request.CreateResponse<Product>(HttpStatusCode.OK,product); } return rm; } }

      WebAPI路由構成了適配器的大部分功能,它們負責解析資源路徑,並將資源參數轉化為string類型參數。ProductService(一個應用服務)實例是注入進來的,請求便是通過該ProductService將處理委派到應用程序內部的。之后,Product對象將被序列化成json字符串,然后放在Response中,再由HTTP輸出端口發出。

      WebAPI並不是我們的關注點

      WebAPI只是使用應用程序和領域模型的一種方式。在這里,WebAPI並不重要,我們完全可以使用其它框架來完成相同的功能。但不管采用哪種方式,不同的適配器都會將輸入委派給相同的API。

      圖中右側的端口和適配器,我們應該如何看待呢?我們可以將資源庫的實現看作是持久化適配器,該適配器用於訪問先前存儲的聚合實例,或者保存新的聚合實例。正如圖中的適配器E、F和G所展示的,我們可以通過不同的方式實現資源庫,比如關系型數據庫、基於文檔的存儲、分布式緩存和內存存儲等。如果應用程序向外界發送領域事件消息,我們將使用適配器H進行處理。該適配器處理消息輸出,而剛才提到的處理MSMQ消息的適配器則是消息輸入的,因此應該使用不同的端口(即選擇六邊形的另外一條邊)。

      六邊形架構的一大好處在於,我們可以輕易地開發用於測試的適配器。整個應用程序和領域模型可以在沒有客戶和存儲機制的條件下進行設計開發。在測試時,我們可以方便地對ProductService進行替換,而無須考慮它是應該支持HTTP/REST呢,還是SOAP,或者是消息端口。任何測試客戶都可以在用戶界面還未完成之前進行開發。在選擇持久化機制之前,我們可以在測試中采用內存資源庫來模擬持久化。更多的內存持久人實現細節,請參考資源庫。如此一來,我們可以在核心領域上進行持續開發,而不需要考慮那些支撐性的技術組件。

      如果你采用的是嚴格分層架構,那么你應該考慮推平這種架構(推平嚴格分層架構),然后開始采用端口與適配器。如果設計得當,內部六邊形——也即應用程序和領域模型——是不會泄漏到外部區域的,這樣也有助於形成一種清晰的應用程序邊界。在外部區域,不同的適配器可以支持自動化測試和真實的客戶請求,還有存儲、消息和其他輸出機制等。

      六邊形架構的功能如此強大,以致於它可以用來支持系統中的其它架構。比如,我們可能采用SOA架構、REST或者事件驅動架構;也有可能采用CQRS;或者數據網織或基於風格的分布式緩存;還有可能采用Map-Reduce這種分布式並行處理方式。六邊形架構為這些架構提供了堅實的支撐基礎。當然,能夠提供這種基礎的不只是六邊形架構,但是一般默認使用這種架構,輔助使用其它架構。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM