Redux VS 命令模式
原文 Redux and The Command Pattern
軟體行業兩大必然事件:
- 框架永遠在變
- 設計模式是軟體工程的基礎
想要最佳實踐,大多都會歸結到設計模式上來。設計模式是由經驗豐富的開發者總結的,它教會我們如何思考。但它不一定是最終的解決方案,如果你有更好的方案,完全可以無視設計模式。
有關設計模式推薦兩本書 《設計模式:可復用面向對象軟體的基礎》 & js相關的《Learning JavaScript Design Patterns》
命令模式
命令模式在構建簡潔解藕的系統框架是非常出色的。它能讓系統在未來某個時刻執行某個部分業務邏輯。Redux 就是來源於此,讓我們了解一下命令模式並把它轉換為Redux
三要素 Receiver, Command,以及 Executor
例子:用代碼描述特斯拉新車Model3的銷售方案
Receiver 命令接收器 保存我們的業務邏輯,每當接受到一個需求它能知道如何去滿足該需求。
/** + 確定需求 + @param model - model of car + @param id - id of car **/function requestInfo(model, id) { return `${model} with id: ${id}`;}/** + 買車 + @param model - model of car + @param id - id of car **/function buyVehicle(model, id) { return `You purchased ${model} with id: ${id}`;}/** + 安排看車 + @param model - model of car + @param id - id of car **/function arrangeViewing(model, id) { return `You have successfully booked a viewing of ${model} (${id})`;}
我們將上述的三個操作封裝到一個控制器裡面:
const TeslaSalesControl = { buyVehicle, requestInfo, arrangeViewing}export default TeslaSalesControl;
Command 命令 包含行為調用的一些信息 通常是一個對象
const sampleCommand = { action: "arrangeViewing", params: [Tesla 3, 1337]};
命令定義了一個行為,執行arrangeViewing的行為。
The Executor 執行器
有了命令 也有了命令接收器(控制器),接下來就是連接他們倆的執行器了。執行器的職責就是將命令傳給命令接收器來並調用接收器裡面的響應函數來完成業務邏輯。
/** + A generic execute function + Takes a receiver and a command **/export default function execute(receiver, command) { return receiver[command.action] && receiver[command.action](...command.params);}
現在我們就可以開始執行這些命令了。
讓業務跑起來
import execute from executor;import TeslaSalesContorl from receiver// 確認需求execute(TeslaSalesContorl, { action:requestInfo, param:[Model S Battery, 1337]});//看車execute(TeslaSalesControl, { action: "arrangeViewing", param: ["Model S", "123"]});//買車execute(TeslaSalesControl, { action: "buyVehicle", param: ["Tesla 3", "23243425"]});
對比Redux
- Store == Receiver
- Action == Command
- Dispatch == Execute
讓我們重新實現一下上面的例子
Store 在Redux中被拆解到各個Reducer當中進行初始化,這些Reducer都是純函數,當被調用的時候就返回一個新的state,而不會導致別的奇怪的事情。這使得代碼高度可預測和可測試性。
Store (Receiver)
import { combineReducers } = redux;function arrangeViewing(state, action) { switch(action.type) { case "ARRANGE_VIEWING": const { model, id } = action.data; return `${model} and ${id}` default: return "" }}function requestInfo(state, action) { switch(action.type) { case "REQUEST_INFO": const { model, id } = action.data; return `${model} and ${id}` default: return "" }}function buyVehicle(state, action) { switch(action.type) { case "BUY_VEHICLE": const { model, id } = action.data; return `${model} and ${id}` default: return false }}const rootReducer = combineReducers({ arrangeViewing, requestInfo, buyVehicle});export default rootReducer;
import { applyMiddleware, createStore } from redux;import createLogger from redux-logger;import ReduxThunk from redux-thunk;import rootReducer from ../imports/client/reducers/rootReducer;// create a loggerconst logger = createLogger();const middleware = [ReduxThunk, logger];const Store = createStore(rootReducer, {}, applyMiddleware(...middleware));export default Store;
Action (Command)
const sampleActionObject = { type: "BUY_CAR", data: { model: "TESLA", id: "1234" }}
Dispatch (Executor)
import Store from store;Store.dispatch({ type: "ARRANGE_VIEWING", data: { model: "Model S", id: "123" }});Store.dispatch({ type: "REQUEST_INFO", data: { model: "Model S Battery", id: "123342" }});Store.dispatch({ type: "BUY_VEHICLE", data: { model: "TESLA 3", id: "23243425" }});
看到了吧,很像!設計模式可以讓你更好的理解架構的本質。
推薦閱讀:
※react中createFactory, createClass, createElement分別在什麼場景下使用,為什麼要這麼定義?
※Rx 的編程方式(一)
※React+Redux打造「NEWS EARLY」單頁應用 一步步讓你理解最前沿技術棧的真諦
※React 源碼剖析系列 - 不可思議的 react diff
※前後分離兼攻守,幹活帶風嗖嗖嗖