Day01 - 緣起:怎麼了?為什麼?如何掌握過於自由的程式碼?
以訂單、RPG 角色的移動,這 2 個例子,描述在複雜的軟體應用、系統中,會面臨的挑戰。
以及我們嘗試如何去克服這個困難
- 透過儲存 boolean
flag
進變數,記憶狀態- 透過一系列
if / else
判斷狀態、進行防呆)
解釋了 Day1 這個解決方案帶來了什麼困擾及難題
- 狀態不具描述性、可讀性低
- 違反開放封閉原則
- 透過一系列
if / else
判斷狀態、進行防呆,當新增、修改功能時
- 要回去改動舊功能的程式碼
- 每新增一個狀態
flag
,除錯複雜度就大幅提升- 狀態描述性下降、可讀性降低
- 溝通成本提升
- 必須注意邏輯之間的連動性、相依性
- 容易漏思考東西
- 容易產生冗余的邏輯語句
- 換個角度觀察
- 獨立的狀態
- 舊狀態 → 新狀態,有明確的轉移路徑
今天我們就要藉著這個新的角度下去討論,接續之前的兩個例子
1.RPG 遊戲的角色移動
2.交易系統的訂單進度
我們可以發現這兩個商業需求其實都是針對一個個體、實體(entity)或是物件(object)出發
訂單進度是針對「訂單」進行追蹤,不同的進度會採取對應的行動。
同樣 RPG 角色中,我們的前進、後退、跳躍、匍匐這些行為,也都時針對玩家選取的「角色」操縱。
前面兩天都有提及狀態一詞,但我們還沒有對這個字有嚴謹的定義。
英文中的 state 及 status 都被翻譯為狀態,既然我們要研究的項目是:有限狀態機(Finite State Machine),我想我們有必要對「狀態」一詞進行釐清。
State: the particular condition that someone or something is in at a specific time.
Status: the situation at a particular time during a process.
by What is the difference between state and status?
state: the physical or mental condition that someone or something is in
status: a situation at a particular time, especially in an argument, discussion etc.
by StackExchange: "Status" vs. "state"
state表示一个确定的状态集中的某个状态(比如水的三态)
status表示一种笼统的情形(比如你的生活状态、工作状态),不存在确定的状态集。
by 知乎:程序代码中,怎么区分status和state?
綜合以上 3 組解釋,我們可以發現
狀態(state):比較偏向實際、實體的狀況或條件 (condition)。比如:水的三態,氣態、液態、固態
狀態(status):比較偏向一段期間的情況或形勢 (situation)。比如:冷戰狀態、工作狀態
而 State 一詞,在 Wiki (Computer Science)中的解釋
在 IT 或 CS 的領域中,如果有一個系統被設計來記憶先前的事件、使用者的互動等。這個被記憶起來的資訊,我們稱為狀態。而我們也稱這個系統是有狀態的(stateful)。
所以在前面兩個例子中,我們必須透過 flag 記憶訂單目前所在階段是什麼、才能根據此採取對應的行動;
RPG 角色的操控,也需要記起上一個行為是什麼,來決定下個行為,是不是合法的(俯臥不能直接跳起)
因此前述所指稱的「狀態」會比較趨近英文中的 "State",在這邊要跟讀者們界定,在本系列文中的「狀態」一詞,除非有另外特別解釋,否則皆應指為 "State" 。
在第 1 點的對象、實體或是物件,解釋完 State 之後,也想在此釐清
在 CS 的領域裡,Object 可以是一個變數、一種資料結構、一個函式、一個方法,換句話說,是一種儲存在記憶體裡面的值,被識別符(identifier,這裡我們比較常聽的是 key 或是 property name 等)參照
by Wiki:Object(computer science
真實世界中的物件都有 2 個特徵,他們都有狀態(state)及行為(behavior),比如狗有狀態(姓名、顏色、品種..)及行為(汪汪叫、搖尾巴...)
by Oracle - Java document :What Is an Object?
我想,以目前所知,現在所指的物件、主體、個體或對象,是會比較關注在這個 Object 底下的狀態;一個主體底下包含的各種狀態。(角色的狀態是跑、跳、匍匐著等)
- 換個角度觀察
- 獨立的狀態
- 舊狀態 → 新狀態,有明確的轉移路徑
能不能直接使用以下的程式碼?不要像第一天還要回頭做過多的防呆檢查...
if(state == '跳躍中') // 畫出跳躍
if(state == '匍匐中') // 畫出匍匐
因為狀態與狀態間是彼此獨立的(玩家不能同時是跳躍中跟匍匐中),而且狀態轉移有明確的路徑。
如果是匍匐中,下一個狀態就不能是跳躍中,只可以是站立
我們能不能設計一個函式讓狀態間彼此不相干擾
let nextState = f(previusState)
假設我們設計出這個 function 之後,能明確切分 state 跟 state 間的關係,也讓我們不必再回去原本狀態底下添加 if/else
防呆,但...
我們發現其實還有個不足之處,就像是 Oracle 對物件的定義是 「狀態」及「行為」。我們發現這個狀態的轉移呀,不單單只依靠 previusState
。
舉例而言,我們的規格書說
除了 previusState
之外,我們還必須注意操縱者的「行為」,或是說 監聽這些 keyboard (按鍵)的「事件」。
所以說那我們明天就繼續來探索這個世界或是行為吧
nextState = f(previusState)
及其不足之處。在 CS 的領域裡,Object 可以是一個變數、一種資料結構、一個韓式、一個方法、一個函式、一個方法,換句話說,是一種儲存在記憶體裡面的值,被識別符(identifier,這裡我們比較常聽的是 key 或是 property name 等)參照
多了一個韓式 :)
感謝,一定是半夜鍵盤肚子餓了
?感謝,一定是半夜鍵盤肚子餓了