建立可維護和可測試的 Windows 表單應用程式的 10 種方法(譯)

建立可維護和可測試的 Windows 表單應用程式的 10 種方法(譯)

我遇到的大多數 Windows 表單應用程式都不存在或單元測試覆蓋率極低。而且它們通常也很難維護,專案中各種 Form 類的程式碼背後有數百甚至數千行程式碼,但它不必是這樣。

最後更新 2021/12/10 下午11:51
Mark Heath
預計閱讀 8 分鐘
分類
Blazor
標籤
.NET Blazor Winform 單元測試

我遇到的大多數 Windows 表單應用程式都不存在或單元測試覆蓋率極低。而且它們通常也很難維護,專案中各種 Form 類別的程式碼背後有數百甚至數千行程式碼,但它不必是這樣。僅僅因為 Windows 表單是一項「遺留」技術,並不意味著你註定會造成無法維護的混亂。下面是建立可維護和可測試的 Windows 表單應用程式的十個技巧。

1. 用使用者控制項隔離你的使用者介面

首先,避免在一個表單上放置太多控制項。通常,你的應用程式的主要形式可以分解為邏輯區域(我們可以稱之為「檢視」)。如果將這些區域中的每個區域的控制項放入它們自己的容器中,那麼你自己的生活就會變得更加輕鬆,而在 Windows 表單中,最簡單的方法是使用使用者控制項。因此,如果你有一個資源管理器樣式的應用程式,左側是樹狀檢視,右側是詳細資訊檢視,則將 TreeView 放入其自己的 UserControl,並為每個可能的右側檢視建立一個 UserControl。同樣,如果你有索引標籤控制項,請為索引標籤控制項中的每個頁面建立一個單獨的 UserControl。

這樣做不僅可以防止你的類別變得難以管理,而且還可以調整大小和設定 Tab 鍵順序等,使任務變得更加簡單。它還允許你在必要時輕鬆地一次性停用使用者介面的整個部分。你也會發現,當你將使用者介面分解為包含邏輯分組控制項的較小 UserControl 時,重新設計應用程式的 UI 佈局會變得更加容易。

2. 將非 UI 程式碼排除在後面的程式碼之外

在 Windows 表單應用程式中,你總是在表單背後的程式碼中找到存取網路、資料庫或檔案系統的程式碼。這嚴重違反了「單一職責原則」。你的 Form 或 UserControl 類別的重點應該只是使用者介面。因此,當你偵測到背後的程式碼中存在與 UI 無關的程式碼時,請將其重構為具有單一職責的類別。因此,你可以建立一個 PreferencesManager 類別,或者一個負責呼叫特定 Web 服務的類別。然後可以將這些類別作為依賴項注入到你的 UI 元件中(儘管這只是第一步——我們可以進一步擴展這個想法,我們很快就會看到)。

3. 用介面建立被動檢視

一種特別有用的技術是使你建立的每個表單和使用者控制項都實作一個檢視介面。此介面應包含允許設定和檢索檢視中控制項的狀態和內容的屬性。它還可能包括報告使用者互動的事件,例如按一下按鈕或移動滑桿。目標是這些檢視介面的實作是完全被動的。理想情況下,你的 Forms 和 UserControls 背後的程式碼中不應該有任何條件邏輯。

下面是一個用於新使用者條目檢視的檢視介面範例。這個檢視的實作應該是微不足道的。任何業務邏輯都不屬於後面的程式碼(我們接下來將討論它屬於哪裡)。

interface INewUserView
{
    string FirstName { get; set; }
    string LastName { get; set; }
    event EventHandler SaveClicked;
}

透過確保你的檢視實作盡可能簡單,你將能夠最大化地遷移到替代 UI 框架(如 WPF),因為你唯一需要做的就是在新技術中重新建立檢視。所有其他程式碼都可以重複使用。

4.使用 presenters 控制檢視

因此,如果你已將所有檢視設為被動並實作介面,則你需要一些能夠實現應用程式業務邏輯並控制檢視的東西。我們可以稱這些為「presenter」類別。這是稱為「模型檢視演示者」或 MVP 的模式。

在模型檢視展示器中,你的檢視是完全被動的,展示器會指示檢視顯示哪些資料。還允許檢視與演示者通訊。在我上面的範例中,它透過引發事件來實現,但通常使用這種模式,你的檢視可以直接呼叫演示者。

絕對不允許檢視開始直接操作模型(包括你的業務實體、資料庫層等)。如果你遵循 MVP 模式,你的應用程式中所有的業務邏輯都可以輕鬆測試,因為它位於 Presenter 或其他非 UI 類別中。

5. 為錯誤報告建立服務

通常,你的演示者類別需要顯示錯誤訊息。但不要只是將 MessageBox.Show 放入非 UI 類別中。你將使該方法無法進行單元測試。而是建立一個服務(比如 IErrorDisplayService),你的演示者可以在需要報告問題時呼叫該服務。這使你的演示者單元保持可測試性,並且還提供了更改將來向使用者呈現錯誤的方式的靈活性。

6. 使用命令模式

如果你的應用程式包含一個帶有大量按鈕供使用者按一下的工具列,則命令模式可能非常適合。命令模式規定你為每個命令建立一個類別。這有很大的好處,可以將你的程式碼分成小類別,每個小類別都有一個責任。它還允許你集中處理與特定命令有關的所有事情。是否應該啟用該命令?它應該是可見的嗎?它的工具提示和快速鍵是什麼?它是否需要特定的特權或許可才能執行?命令執行時拋出的異常應該如何處理?

命令模式允許你標準化處理應用程式中所有命令所共有的每個問題的方式。你的命令物件將有一個 Execute 方法,該方法實際上包含為該命令執行所需行為的程式碼。在許多情況下,這將涉及呼叫其他物件和業務服務,因此你需要將它們作為依賴項注入到命令物件中。你的命令物件本身應該可以(並且直接)進行單元測試。

7. 使用 IoC 容器管理依賴項

如果你正在使用 Presenter 類別和 Command 類別,那麼你可能會發現它們所依賴的類別的數量隨著時間的增長。這是 Unity 或 StructureMap 等控制反轉容器真正可以幫助你的地方。無論它們具有多少層級的依賴關係,它們都允許你輕鬆建置檢視和演示器。

8. 使用事件聚合器模式

另一種在 Windows 表單應用程式中非常有用的設計模式是事件聚合器模式(有時也稱為「信使」或「事件匯流排」)。這是一種模式,其中事件的引發者和事件的處理者根本不需要相互耦合。當你的程式碼中發生需要在其他地方處理的「事件」時,只需向事件聚合器發佈一條訊息即可。然後需要回應該訊息的程式碼可以訂閱和處理它,而無需擔心是誰提出的。

例如,你發送一條「請求幫助」訊息,其中包含使用者目前在 UI 中的位置的詳細資訊。然後另一個服務處理該訊息並確保在網頁瀏覽器中啟動說明文件中的正確頁面。另一個例子是導航。如果你的應用程式有多個畫面,則可以將「導航」訊息發佈到事件聚合器,然後訂閱者可以透過確保新畫面顯示在使用者介面中來回應該訊息。

除了從根本上分離事件的發佈者和訂閱者之外,事件聚合器還具有建立極易進行單元測試的程式碼的巨大好處。

9. 使用 Async 和 Await 進行執行緒處理

如果你的目標是 .NET 4 及更高版本並使用 Visual Studio 12 或更高版本,請不要忘記你可以使用新的 async 和 await 關鍵字,這將大大簡化應用程式中的任何執行緒程式碼,並自動處理回送後台任務完成後進入 UI 執行緒。它們還極大地簡化了跨多個鏈式後台任務的異常處理。它們非常適合 Windows 表單應用程式,如果你還沒有的話,非常值得一試。

10.不要太晚

可以將我上面描述的所有模式和技術改造為現有的 Windows 表單應用程式,但我可以從痛苦的經驗告訴你,這可能需要大量工作,尤其是當表單背後的程式碼達到數千行時。如果你開始使用 MVP、事件聚合器和命令模式等模式建置應用程式,你會發現隨著它們變得越來越大,維護起來會少很多痛苦。你還可以對所有業務邏輯進行單元測試,這對於持續的可維護性至關重要。

原文作者:Mark Heath

原文鏈結:https://markheath.net/post/maintainable-winforms

轉載自微信公眾號: OneByOneDotNet

公眾號文章鏈結:https://mp.weixin.qq.com/s/ks_ghCRxMmOQPYFib0cb3g

繼續探索

延伸閱讀

更多文章
同分類 / 同標籤 2024/2/29

Winform中也可以這樣做資料展示

在做winform開發的過程中,經常需要做資料展示的功能,之前一直使用的是gridcontrol控制項,今天想透過一個範例,跟大家介紹一下如何在winform blazor hybrid中使用ant design blazor中的table元件做資料展示。

繼續閱讀
同分類 / 同標籤 2024/2/29

Winform的介面也可以變好看?

前幾天跟大家介紹了在winform中使用blazor hybrid,而且還說配上blazor的UI可以讓我們的winform程式設計的更加好看,接下來我想以一個在winform blazor hybrid中繪圖的範例來進行說明,希望對你有所幫助。

繼續閱讀
同分類 / 同標籤 2024/1/7

碼坊「文章標題URL別名生成器」上線

碼坊是站長新開的一個提供網頁在線工具、跨平台桌面和手機應用的開源專案。站長將終致力於為你帶來更高效、更便捷的使用體驗。今天,站長榮幸地推出「文章標題URL別名生成器」,幫助你輕鬆創建文章標題的URL別名,提升SEO效果和用戶體驗。快來碼坊,探索更多實用工具吧!

繼續閱讀