架構案例研究
透過一個實現 MVVM 架構模式的 Flutter 應用進行詳細剖析。
本指南中的程式碼示例來自 Compass 示例應用,該應用旨在幫助使用者構建和預訂旅行行程。這是一個功能完備的示例應用,擁有豐富的功能、路由和螢幕。該應用與 HTTP 伺服器通訊,具備開發和生產環境,包含品牌特定的樣式,並擁有較高的測試覆蓋率。透過這些方式,它模擬了一個真實的、功能豐富的 Flutter 應用。




Compass 應用的架構最接近 Flutter 應用架構指南中所述的 MVVM 架構模式。本架構案例研究透過剖析 Compass 應用的“首頁”功能,演示瞭如何實現這些指南。如果你不熟悉 MVVM,建議先閱讀這些指南。
Compass 應用的首頁顯示了使用者賬戶資訊和已儲存的旅行列表。在此螢幕上,你可以登出、開啟詳細的旅行頁面、刪除已儲存的旅行,以及導航到核心應用流程的第一頁,從而允許使用者構建新的行程。
在本案例研究中,你將學習以下內容:
- 如何透過在資料層使用倉庫(Repository)和服務(Service),以及在介面層使用 MVVM 架構模式來實現 Flutter 的應用架構指南。
- 如何使用命令模式(Command pattern)在資料變化時安全地渲染 UI。
- 如何使用
ChangeNotifier和Listenable物件來管理狀態。 - 如何使用
package:provider實現依賴注入(Dependency Injection)。 - 如何在遵循推薦架構的情況下設定測試。
- 針對大型 Flutter 應用的有效包結構。
本案例研究按順序閱讀編寫。任何頁面都可能引用前面的頁面。
本案例研究中的程式碼示例包含了理解架構所需的所有細節,但它們不是完整的、可執行的程式碼片段。如果你更喜歡跟隨完整的應用學習,可以在 GitHub 上找到它。
包結構
#組織良好的程式碼更便於多位工程師協作,減少程式碼衝突,也更容易讓新加入的工程師理解和上手。良好的程式碼組織既得益於定義明確的架構,也能促進架構的完善。
組織程式碼有兩種流行方式:
- 按功能劃分 - 將每個功能所需的類歸為一組。例如,你可能有一個
auth目錄,其中包含auth_viewmodel.dart、login_usecase.dart、logout_usecase.dart、login_screen.dart、logout_button.dart等檔案。 - 按型別劃分 - 將每種“型別”的架構元件歸為一組。例如,你可能擁有
repositories、models、services和viewmodels等目錄。
本指南推薦的架構結合了這兩種方式。資料層物件(倉庫和服務)不繫結到單個功能,而 UI 層物件(檢視和檢視模型)則繫結到特定功能。以下是 Compass 應用中程式碼的組織方式。
-
lib/
ui/
core/
ui/
- <shared_widgets>
- themes/
<feature_name>/
view_models/
- <view_model_class>.dart
widgets/
- <feature_name>_screen.dart
- <other_widgets>
domain/
models/
- <model_name>.dart
data/
repositories/
- <repository_class>.dart
services/
- <service_class>.dart
model/
- <api_model_class>.dart
- config/
- utils/
- routing/
- main_staging.dart
- main_development.dart
- main.dart
-
test/// 包含單元測試和元件測試。
- data/
- domain/
- ui/
- utils/
-
testing/// 包含其他類執行測試所需的模擬物件 (mocks)。
- fakes/
- models/
大部分應用程式碼位於 data、domain 和 ui 資料夾中。Data 資料夾按型別組織程式碼,因為倉庫和服務可以在不同的功能之間被多個檢視模型共享。Ui 資料夾按功能組織程式碼,因為每個功能恰好有一個檢視和一個檢視模型。
此資料夾結構的其他顯著特點:
- UI 資料夾還包含一個名為“core”的子目錄。Core 包含由多個檢視共享的元件和主題邏輯,例如帶有品牌樣式的按鈕。
- Domain 資料夾包含應用資料型別,因為它們被資料層和 UI 層共同使用。
- 該應用包含三個“main”檔案,分別作為開發、預釋出(staging)和生產環境的應用入口點。
- 在
lib同級目錄下有兩個與測試相關的目錄:test/包含測試程式碼,其結構與lib/對應。testing/是一個子包,包含可用於其他包測試程式碼的模擬物件和其他測試工具。testing/資料夾可以描述為你不釋出的那部分應用內容,也就是被測試的內容。
Compass 應用中還有一些與架構無關的附加程式碼。如需檢視完整的包結構,請在 GitHub 上檢視。
其他架構選項
#本案例研究中的示例演示了一個應用如何遵循我們推薦的架構規則,但實際上還有許多其他編寫應用的方式。此應用的 UI 嚴重依賴於檢視模型和 ChangeNotifier,但它完全可以用流(streams)或使用其他庫(如 riverpod、flutter_bloc 和 signals)來編寫。此應用各層之間的通訊全權透過方法呼叫處理,包括輪詢新資料。它也可以改用流來將資料從倉庫暴露給檢視模型,同時依然遵循本指南所涵蓋的規則。
即使你完全遵循本指南且不引入額外的庫,你仍然需要做出抉擇:是否需要領域層(domain layer)?如果需要,如何管理資料訪問?答案很大程度上取決於團隊的具體需求,因此沒有唯一的標準答案。無論你如何回答這些問題,本指南中的原則都將幫助你編寫可擴充套件的 Flutter 應用。
如果仔細觀察,其實所有架構本質上都是 MVVM,不是嗎?
反饋
#隨著網站該部分的完善,我們歡迎你的反饋!