細節:內部和外部的代碼如何組織?
除了上面提到的原則,我們完全可以自由地按照我們的意愿在每個區域內組織代碼。
關于業務代碼,內部,一個好主意是選擇根據業務邏輯組織其模塊(或目錄)。
要避免的一個組織是按類型對類進行分組。例如“ports”目錄,或“repositories”目錄(如果使用此模式)或“services”目錄。在您的業務代碼中考慮100%的業務,包括組織您的模塊或目錄!理想的情況是能夠打開目錄或業務邏輯模塊,并立即了解您的程序解決的業務問題;而不是只看到“存儲庫”,“服務”或其他“經理”目錄。
另請參閱此主題:
https://medium.com/@msandin/strategies-for-organizing-code-2c9d690b6f33
https://martinfowler.com/bliki/PresentationDomainDataLayering.html
細節:運行時
您如何實例化所有這些以滿足運行時依賴性?如果您使用依賴注入框架,則可能不需要問自己這個問題。但我認為要理解六邊形體系結構,看看應用程序啟動時會發生什么是很有趣的。要做到這一點,至少在本文的時候不要使用依賴注入框架。
例如,如果我們手動實例化一切,我們將如何編寫應用程序的入口點:
class Program
{
static void Main(string[] args)
{
// 1. Instantiate right-side adapter ("go outside the hexagon")
IObtainPoems fileAdapter = new PoetryLibraryFileAdapter(@".\\Peoms.txt");
// 2. Instantiate the hexagon
IRequestVerses poetryReader = new PoetryReader(fileAdapter);
// 3. Instantiate the left-side adapter ("I want ask/to go inside")
var consoleAdapter = new ConsoleAdapter(poetryReader);
System.Console.WriteLine("Here is some...");
consoleAdapter.Ask();
System.Console.WriteLine("Type enter to exit...");
System.Console.ReadLine();
}
}
實例化順序通常是從右到左:
- 首先我們實例化Infrastructure端,這里是fileAdapter,它將讀取文件。
- 我們實例化將由應用程序驅動的Domain類,poetryReader在其中通過注入將fileAdapter注入構造函數。
- 安裝Application端,consoleAdapter將驅動poetryReader并寫入控制臺。這里poetryReader通過注入構造函數注入consoleAdapter。
我們說內部不應該依賴于外部。那么為什么我們將來自Infrastructure的代碼fileAdapter注入poetryReader,這是來自Domain的代碼?
我們可以這樣做,因為通過查看模式和代碼,除了是PoetryLibraryFileAdapter(基礎結構方面)之外,fileAdapter也是繼承的IObtainPoems實例。
在實踐中,PoetryReader不依賴于PoetryLibraryFileAdapter,而是依賴于IObtainPoems,它在域中定義良好。您可以通過查看其構造函數的簽名來檢查它。
public PoetryReader(IObtainPoems poetryLibrary)
{
this.poetryLibrary = poetryLibrary;
}
PoetryLibraryFileAdapter和PoetryReader是弱耦合的。
細節:右側的依賴性反轉
fileAdapter依賴于業務的定義(依賴于繼承),但在運行時poetryReader可以在實踐中控制fileAdapter的實例是依賴倒置的經典案例。
實際上,如果沒有IObtainPoems接口,業務代碼將依賴于其定義的基礎結構,我們希望避免:
該接口允許反轉此依賴關系的方向:
除了使業務獨立于外部系統之外,右側的此接口還允許滿足著名的 SOLID或Dependency Inversion Principle原則。這個原則說:
- 高級模塊不應該依賴于低級模塊。兩者都必須依賴于抽象。
- 抽象不應該依賴于細節。細節必須取決于抽象。
如果我們沒有接口,我們將擁有一個依賴于低級模塊(Infrastructure)的高級模塊(Domain)。
注意:對于左側和業務代碼之間的交互,依賴性自然是正確的方向。
交互實現的這種差異與應用程序域和域 - 基礎架構關系之間的差異有關。提醒:應用程序端驅動域,而基礎架構端由域驅動。
細節:為什么左邊有接口?
由于Application和Domain之間的依賴關系已經在正確的方向上,因此IRequestVerses接口的作用不是反轉依賴關系。
但是,它仍然有興趣:明確限制應用程序代碼和域代碼之間的耦合表面。
實際上,PoetryReader類可以有除IRequestVerses接口之外的其他方法。ConsoleAdapter不了解這一點很重要。
它與另一個SOLID原則 - 接口隔離原則一致。
客戶不應該被迫依賴他們不使用的方法。
但是,一旦你理解了意圖,如果左側的端口只有一個方法,并且它的實現只有一個方法,如我們的例子,接口真的是必要的嗎?在動態語言中,最終將通過duck typing?
我們可以回答一個問題:您的團隊對此有何看法?每個人都清楚隔離目標,甚至不需要界面來觸發對話嗎?這取決于你完全決定。
六角形結構測試
該軟件架構的一個重要優點是它有助于測試自動化,這是其原始意圖的一部分。
如何從Application端替換一些代碼?
在一般情況下,左側代碼的作用可以由測試框架直接扮演。實際上,測試代碼可以直接驅動業務邏輯代碼。
注意:該圖說明了集成測試,因為沒有替換正確的部分。它也可以替換,見下文。
如何替換基礎設施方面的一些代碼?
右邊的代碼必須由業務驅動。通常,如果要編寫單元測試,可以使用模擬或任何其他形式的測試雙重替換它,具體取決于您要測試的內容。
達到了目標!
允許應用程序由用戶,程序,自動化測試或批處理腳本驅動,并與其可能的執行系統和數據庫隔離開發和測試。
小心!這并不妨礙您測試應用程序和基礎結構代碼,任何值得測試的代碼。在這個主題上,我再次向您推薦實踐測試金字塔系列。
事實上,通過組合我們替換或不替換的內容,我們可以看到,通過這種架構,我們可以測試我們想要的東西:
- 整個域單獨,
- 在Infrastructure端獨立地集成Application和Domain
- 在應用程序端獨立地集成域和基礎結構
-
Web
+關注
關注
2文章
1269瀏覽量
69732 -
代碼
+關注
關注
30文章
4828瀏覽量
69055
發布評論請先 登錄
相關推薦
MC14069UBDR2G六角逆變器的相關資料推薦
一種改進的六角形砍邊細分方法
MC14069UBDR2G六角逆變器
![MC14069UBDR<b class='flag-5'>2</b>G<b class='flag-5'>六角</b>逆變器](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
外六角和內六角螺栓,該如何選擇?
六角架構學的三個原則和技術1
![<b class='flag-5'>六角</b><b class='flag-5'>架構</b><b class='flag-5'>學</b>的<b class='flag-5'>三個</b><b class='flag-5'>原則</b>和<b class='flag-5'>技術</b>1](https://file.elecfans.com/web2/M00/93/86/pYYBAGP1gW2ASSPKAABQu0XVMGs080.jpg)
評論