跳到主內容

常見架構概念

瞭解應用程式設計中的常見架構概念,以及它們如何應用於 Flutter。

在本節中,你將瞭解到在更廣泛的應用開發領域中指導架構決策的成熟原則,以及它們如何具體融入 Flutter 的資訊。這是對推薦架構和最佳實踐相關的術語和概念的初步介紹,你可以在本指南的後續部分中深入探索它們。

關注點分離

#

關注點分離 (Separation-of-concerns) 是應用開發中的核心原則,它透過將應用程式的功能劃分為獨立的、自包含的單元來促進模組化和可維護性。從高層來看,這意味著將 UI 邏輯與業務邏輯分離開來。這通常被稱為分層架構。在每一層中,你應該進一步按功能點對應用程式進行細分。例如,應用程式的身份驗證邏輯應該與搜尋邏輯位於不同的類中。

在 Flutter 中,這也適用於元件 (widgets)元件 (Widget)構建 Flutter 使用者介面的基本單元。瞭解更多在 UI 層也是如此。你應該編寫可複用、精簡的元件,並儘量少地在其中編寫邏輯。

分層架構

#

Flutter 應用程式應該分編寫。分層架構是一種軟體設計模式,它將應用程式組織成不同的層,每一層都有特定的角色和職責。通常情況下,根據複雜程度,應用程式被分為 2 到 3 層。

The three common layers of app architecture, the UI layer, logic layer, and data layer.
  • UI 層 - 向用戶顯示由業務邏輯層暴露的資料,並處理使用者互動。這通常也被稱為“表現層”。
  • 邏輯層 - 實現核心業務邏輯,並促進資料層和 UI 層之間的互動。通常被稱為“領域層”。邏輯層是可選的,僅當你的應用程式在客戶端擁有複雜的業務邏輯時才需要實現。許多應用只關心向使用者展示資料並允許使用者更改該資料(通常稱為 CRUD 應用)。這些應用可能不需要這一可選層。
  • 資料層 - 管理與資料來源的互動,例如資料庫或平臺外掛。向業務邏輯層暴露資料和方法。

這些被稱為“層”,因為每一層只能與直接位於其下方或上方的層進行通訊。UI 層不應該知道資料層的存在,反之亦然。

單一資料來源

#

應用程式中的每種資料型別都應該有一個單一資料來源 (SSOT)。資料來源負責表示本地或遠端狀態。如果資料可以在應用中被修改,那麼 SSOT 類應該是唯一能夠進行修改的類。

這可以顯著減少應用程式中的 Bug 數量,並簡化程式碼,因為你永遠只會擁有同一份資料的副本。

通常,應用程式中任何給定型別資料的“資料來源”都儲存在一個稱為 Repository(儲存庫)的類中,該類屬於資料層。通常,應用中的每種型別的資料都有一個儲存庫類。

這一原則不僅可以跨越應用程式的各層和元件,還可以應用於單個類內部。例如,一個 Dart 類可以使用 Getter 從 SSOT 欄位派生值(而不是擁有多個需要獨立更新的欄位),或者使用記錄 (records) 列表來對相關值進行分組(而不是使用可能導致索引不同步的並行列表)。

單向資料流

#

單向資料流 (UDF) 是指一種有助於將狀態與顯示該狀態的 UI 解耦的設計模式。簡單來說,狀態從資料層流向邏輯層,最終流向 UI 層中的元件。來自使用者互動的事件則沿相反方向流動:從表現層回傳至邏輯層,再到資料層。

The three common layers of app architecture, the UI layer, logic layer, and data layer, and the flow of state from the data layer to the UI layer.

在 UDF 中,從使用者互動到重新渲染 UI 的更新迴圈如下所示:

  1. [UI 層] 由於使用者互動(例如點選按鈕)引發事件。元件的事件處理器回撥會呼叫邏輯層中某個類暴露的方法。
  2. [邏輯層] 邏輯類呼叫儲存庫暴露的方法,這些方法知道如何修改資料。
  3. [資料層] 儲存庫更新資料(如有必要),然後將新資料提供給邏輯類。
  4. [邏輯層] 邏輯類儲存其新狀態,並將其傳送給 UI。
  5. [UI 層] UI 顯示檢視模型 (view model) 的新狀態。

新資料也可以從資料層開始。例如,儲存庫可能會輪詢 HTTP 伺服器以獲取新資料。在這種情況下,資料流僅走過程的後半部分。最重要的思想是,資料變更始終發生在 SSOT 中,即資料層。這使得你的程式碼更易於理解、更不容易出錯,並防止了畸形或意外資料的產生。

UI 是(不可變)狀態的函式

#

Flutter 是宣告式的,這意味著它構建的 UI 反映了應用程式的當前狀態。當狀態發生變化時,你的應用應該觸發 UI 重建以依賴該狀態。在 Flutter 中,你常聽到的一種說法是“UI 是狀態的函式”。

UI is a function of state.

至關重要的是,由資料驅動 UI,而不是反之。資料應該是不可變的且持久的,而檢視應該包含儘可能少的邏輯。這最大限度地減少了應用程式關閉時資料丟失的可能性,並使你的應用更具可測試性,對 Bug 的抵抗力更強。

可擴充套件性

#

每個架構元件都應該有定義明確的輸入和輸出列表。例如,邏輯層中的檢視模型應該只接收資料來源(如儲存庫)作為輸入,並且只應暴露為檢視格式化的命令和資料。

以這種方式使用清晰的介面,允許你替換類的具體實現,而無需更改任何呼叫該介面的程式碼。

可測試性

#

使軟體可擴充套件的原則也使軟體更易於測試。例如,你可以透過模擬儲存庫來測試檢視模型的自包含邏輯。檢視模型測試不需要你模擬應用程式的其他部分,並且你可以將 UI 邏輯與 Flutter 元件本身分開測試。

你的應用也將更加靈活。新增新的邏輯和 UI 將變得簡單且風險較低。例如,新增一個新的檢視模型不會破壞資料層或業務邏輯層的任何邏輯。

下一節將解釋應用程式架構中任何給定元件的輸入和輸出概念。

反饋

#

由於網站的這一部分正在不斷完善,我們歡迎你的反饋