JavaScript Structural Pattern For Project 開箱 JavaScript 設計模式 (2-3)

me
林彥成
2023-05-30 | 3 min.
文章目錄
  1. 1. Model View Controller Pattern (MVC)
  2. 2. Model-View-ViewModel Pattern (MVVM)
  3. 3. Flux Pattern

這篇文章接下來會讓優化從開資料夾開始,從優化專案結構的三種設計模式切入

  • Model View Controller Pattern (MVC)
  • Model-View-ViewModel Pattern (MVVM)
  • Flux Pattern

Design Patterns 依照目的分成三群:

Model View Controller Pattern (MVC)

Model View Controller (MVC) 模式是一種用於管理程式的結構和邏輯,提供定義清晰的架構,開發上能夠更容易地理解、擴展和測試,架構主要分為三個部分:

  • Model: 處理數據的讀取、寫入和驗證等業務邏輯操作
  • View: 處理數據的顯示和呈現以及用戶互動,可以是 HTML 樣板、頁面元素
  • Controller: 接收來自界面的輸入和事件,並根據這些輸入和事件來更新模型和 UI

MVC 是將應用程式的邏輯、數據和界面分離,達到結構化和可重用性。

  1. 第一種是依照資料表去做區分,把同個資料表的 model、controller、route 集中存放,覺得較適合大型專案。
├── src/
│  ├── entities/                # 按照資料表去區分
│  │  └── user/                 # 使用者表
│  │     ├── model.js           # Schema 定義
│  │     ├── controller.js      # 資料庫 CRUD
│  │     └── route.js           # API 設定
│  └── index.js                 # 入口
├── .eslintrc                   # ESLint 設定檔
├── package-lock.json
├── package.json
└── README.md
  1. 第二種則是依照功能性,controller、routes、models 集中放置在各自的分類資料夾,覺得較適合小型專案。
├── src/
│  ├── controller/              # 資料庫 CRUD
│  ├── routes/                  # API 設定
│  ├── models/                  # Schema 定義
│  └── index.js                 # 程式入口
├── .eslintrc                   # ESLint 設定檔
├── package-lock.json
├── package.json
└── README.md

Model-View-ViewModel Pattern (MVVM)

Model-View-ViewModel Pattern (MVVM) 著重在開發的關注點分離並提供單向或是雙向的 Data Binding 來控制 UI 的顯示邏輯。

  • Model: 定義資料結構,執行資料操作,在 React 中通常是元件中或是 Store 裡的狀態
  • View (stateless): UI 介面,根據 ViewModel 來顯示,實際上的 HTML element 由 JSX 背後的 virtual dom 所控制
  • ViewModel (stateful): 處理 Model 和 View 之間的溝通,用來維護 UI 的狀態,在 React 中的 JSX 就是扮演這個腳色

一個常見的 MVVM 資料流:

  1. ViewModel 從 Model 擷取資料並準備在 View 顯示
  2. View 把和 ViewModel binding 的資料顯示在 UI 中
  3. 透過 View 觸發命令或輸入事件
  4. ViewModel 監控互動並執行資料操作並更新 Model
  5. 如果 Model 資料變更,ViewModel 會通知視圖讓 UI 重新渲染

Flux Pattern

Flux pattern 是由 Facebook 提出將狀態中央化管理的機制,定義了單向資料流的架構明確將程式分為四個核心概念:

  • Actions: 描述事件,例如使用者操作或 API 請求完成,由 type 和 payload 組成
  • Dispatcher: 提供中央管理的機制,用於接收和發送 Actions,當事件發生時,Actions 會被集中到 Dispatcher 並操作對應的 Store
  • Stores: 負責存儲和管理應用程式的狀態,只接受 Dispatcher 過來的 Actions,並根據 Action Type 來更新狀態
  • Views: UI 訂閱 Store 的變化,並依據狀態來更新。當用戶進行操作時,UI 會產生 Action 並送到 Dispatcher 中去跟 Store 互動

搭配 Redux 後,主要就是增加元件之間需要溝通工具,會有以下特性:

  • 單向資料流
  • 公共的狀態儲存 (Store)

專案架構也會受到這種概念去分類:

  • actions: 觸發狀態改變用的 function
  • pages: 頁面容器元件
  • containers: 有連接 Store
  • components: 沒有連接 Store
  • reducers: 收到 action 後的資料邏輯

所以專案資料夾架構依照屬性去分類就會長成下面這個樣子,在完成任務的過程中需要在多個不同的資料夾中來回,覺得較適合小型專案。

└── src
    ├── actions
    │   ├── typeOneActions.js
    │   └── typeTwoActions.js
    ├── api
    │   ├── apiHandler.js
    │   ├── typeOneApi.js
    │   └── typeTwoApi.js
    ├── components
    │   ├── TypeOneComponent.jsx
    │   ├── TypeOneListComponent.jsx
    │   ├── TypeTwoComponent.jsx
    │   ├── TypeTwoPageComponent.jsx
    │   └── HomePageComponent.jsx
    ├── containers
    │   ├── TypeOneContainer.js
    │   └── TypeTwoPageContainer.js
    ├── pages
    │   └── HomePageContainer.js
    ├── index.js
    ├── reducers
    │   ├── typeOneReducer.js
    │   └── typeTwoReducer.js
    ├── routes.js
    ├── store.js
    └── utils

之前弄的小專案當例子,如果有加上 redux 的話,專案架構大概會長成下面的樣子,在比較簡單的專案中可以更簡化。

├── .storybook
├── src/
│  ├── constants/
│  ├── utils/
│  ├── pages/
│  ├── containers/              # containers 放置與 Redux 連接的相關元件,單元測試檔案為 `元件名稱.test.js`
│  ├── components/              # components 放置相關元件,單元測試檔案為 `元件名稱.test.js`
│  │  └── Root.js               # 路由根目錄
│  ├── hooks/                   # hooks 相關
│  ├── middleware/              # 資料處理相關
│  │  ├── API.js                # axios 的 instance
│  │  └── redux-api.js          # redux-api
│  ├── styles/                  # 樣式檔們
│  ├── index.js                 # 程式入口
│  ├── serviceWorker.js
│  └── setupTests.js            # 測試相關設定
├── .eslintrc                   # ESLint 設定檔
├── .prettierrc                 # prettierrc 工具設定
├── .travis.yml                 # 持續發佈工具
├── package-lock.json
├── package.json
└── README.md

在使用 Redux 的時候,我們通常要同時維護 reducer 以及 action,如果還要搭配 API 進行,又會需要多維護一個 middleware。

可是在簡單的專案中,絕大多數時候我們進行的工作都是類似的,官方也有相關的建議,甚至後來還推出了 toolkit 來協助寫法簡化。

簡單來說,本來要維護三個地方,現在變成只要維護一份配置檔就好了。

src
└── features
    ├── typeOne
    │   ├── TypeOne.js
    │   ├── TypeOne.styles.scss
    │   └── typeOneSlice.js
    ├── typeTwo
    │   ├── TypeTwo.js
    │   ├── TypeTwo.styles.scss
    │   └── typeTwoSlice.js
    └── typeThree
        ├── TypeThree.js
        ├── TypeThree.styles.scss
        └── typeThreeSlice.js

喜歡這篇文章,請幫忙拍拍手喔 🤣


share