Woody Liu
4 min readAug 25, 2022

MVVM & Redux_Page.2

previous

前言

還記得上一章介紹 Reducer<State, Action> 缺點時提到。

  • 沒有 Model 層的接口,不利於 Reuse 與 測試。
  • Action 無法串接成 Action Chain,無法循環利用。

這一章節將會引入 Environment 與 Action 循環兩個功能。

Code Review

Utility
└── ViewModelComponents
├── BasicActionExcutorViewModel.swift
├── CellViewModelConfigureHandler.swift
├── ExcuteAction.swift
└── TableViewModelProtocol.swift

Environment

typealias Reducer<State, Action, EnvironmentModel> = (inout State, Action, inout EnvironmentModel)->()

Reducer<State, Action, Environment>

  • Environment: Reducer 的第三個參數,提供 Method 與 外部參數的接口。
  • 使用策略模式,在執行 reducer 時注入其中,可達到商業邏輯可 Reuse 也可建立 Fake 方便編寫測試。

Action 循環

typealias Reducer<State, Action, EnvironmentModel> = (inout State, Action, inout EnvironmentModel)->(Action)?

class BasicActionExcutorViewModel<State, Action, EnvironmentModel>: ActionExcutor {
func excute(_ action: Action) {
if let action = reducer(&state, action, &environment) {
excute(action)
}
}
}

// 正確 example:

let reducer = Reducer { state, action, envi in

switch action {
case a:
// do something
return Action.c
case b:
// do something.
return Action.c
case c:
// do something
return nil
}
}

// 錯誤example :

let reducer = Reducer { state, action, envi in

switch action {
case a:
// do something
return Action.b
case b:
// do something.
return Action.a
case c:
// do something
return nil
}
}

注意:Action.a and Action.b 造成無限循環,在設計時要小心。

Reducer return 下一步動作的 action,再利用 Recursion 機制做遞迴呼叫。 如 BasicActionExcutorViewModel func excute(_ action:) 達到 action 可組裝 與 重復使用。

優點

  • Environment 利於測試與reuse
  • action 串接讓邏輯可以串接,讓程式碼更易於符合單一原則。(註1)

缺點

  • action 無法在異步任務中達成串接功能。
  • environment 的封裝異步任務,對於任務管理的需求增加設計難度。

註一:Action 可串接的設計,利於編寫代碼時更易於習慣拆分邏輯,讓method更趨向 unint 的特性

後言:

接下來就不會再優化Reducer 的功能,因為要處理異步的需求的話,以當前的iOS版本,自己編寫輪子工程太大,建議使用功能完整且高度優化的三方庫來達成,比如 SwiftRex, TCA