紀錄 O'REILLY 深入淺出物件導向分析與設計 (Head First Object-Oriented Analysis & Design) 的讀後心得,並將範例轉為 C#.Net Code。
什麼是「需求」?
【客戶所需之物】稱之為需求。
「需求」是【系統】為了正確運作所必須做的特定事。
「需求」是【設計】的原動力。
收集需求 - 給客戶所需之物
使用案例(Use Case):A use case describes what your system does to accomplish a particilar customer goal. (使用案例描述系統為達成特定客戶目標所要做的事)
- 清楚的價值
- 起點與終點
- 外部啟動者
每個系統都至少包含一個「使用案例」。「使用案例」除了用來收集需求外,另一個更重要的目的,是找出使用時的例外情況,並做替代路徑規劃,而且是在真實世界中確實可行的。
確認系統中所有的「使用案例」有涵蓋了系統的所有需求。
運用使用案例找出客戶忘了告訴你的事。
需求變更 - 山可移,此情永不渝...現在,情況有變
永遠不變的真理 - 就是【改變】。
客戶永遠是對的,只要有付出對等的價格。
每個使用案例至少包含一個「使用情節」,每個使用情節的起點與終點都是相同的,只是路徑不同而已。
透過使用案例接露任何不完整、缺漏的需求,並須考是否需要將其加入系統中。
OO原則:將變化之物封裝起來。
分析 - 將你的軟體帶進真實的世界
本文分析(Textual Analysis):查看使用案例裡的名詞與動詞,並整理出類別與方法。
- 名詞:類別
- 動詞:方法
分析的目的在於確保軟體在真實世界的情境裡仍能正常運作,而不是只在完美的環境裡運行。
本文分析幫你將使用案例轉換成類別、屬性與操作。
範例
專案:介好鑽狗門
第一個客戶的需求:想要一個由按鈕控制的狗門。
第一次使用:狗狗吠著要出去 -> 主人聽到狗狗在吠 -> 主人按下遙控去按鈕 -> 狗門開啟 -> 狗狗順利出門 -> 狗狗完事後回來了 -> 狗狗順利進門 -> ... (過了一段時間) ... -> 家裡怎麼多了隻兔子??
第一次客訴:「@$&*#%(!^_...)」。
第一次檢討:「我的設計沒問題,是客戶在狗狗進門後,忘記再按一次遙控器將門關上。是客戶使用方式不正確,不是我的錯!」
第一次結果:NG,退貨收場。
重新檢討,改變作法,請聽客戶的聲音,了解客戶的需求,建立需求清單,規畫主要路徑與替代路徑,完成第一個使用案例。
//使用案例:狗門(v1.0)
1. 狗狗吠著要出去
2. 主人聽到狗狗在吠
3. 主人按下遙控去按鈕
4. 狗門開啟
5. 狗狗跑出去
6. 狗狗辦它的事
7. 狗狗回來、進門
8. 狗門自動關閉
思考例外情況:萬一狗狗在回來之前,狗門已關上了怎麼辦?
//使用案例:狗門(v1.1)
...
6. 狗狗辦它的事
6.1 狗門自動關閉
6.2 狗狗吠著要進來
6.3 主人聽到狗狗在吠
6.4 主人按下遙控器按鈕
6.5 狗門開啟
7. 狗狗回來、進門
...
【需求新增】
第二個客戶的需求:狗狗每次出門都弄得髒兮兮,希望狗狗每次一出去就關門,直到我將它清理乾淨後按下按鈕讓它進來。
第三個客戶的需求:狗狗經常在吠,根本搞不清楚是不是要出去,能設計狗狗抓門時就打開嗎?
//使用案例:狗門(v2.0)
1. 狗狗想出去
case 1 : (for customer #1&2)
1.1.1. 狗狗吠著要出去
1.1.2. 主人聽到狗狗在吠
1.1.3. 主人按下遙控去按鈕
case 2: (for customer #3)
1.2.1. 狗狗抓門
2. 狗門開啟
3. 狗狗跑出去
4. 狗門自動關閉(for customer #2,但強制擴大到所有用戶)
5. 狗狗辦它的事
6. 狗狗回來
case 1 : (for customer #1)
6.1.1. 很乾淨、吠著要進來
6.1.2. 主人聽到狗狗在吠
6.1.3. 主人按下遙控器按鈕
case 2 : (for customer #2)
6.2.1. 弄得髒兮兮
6.2.2. 主人把狗狗清理乾淨
6.2.3. 主人按下遙控器按鈕
case 3 :(for customer #3)
6.3.1. 狗狗抓門
7. 狗門開啟
8. 狗狗進門
9. 狗門自動關閉
【需求變更】
第一個客戶的需求變更:由於經常沒注意到狗狗在吠,或找不到遙控器,導致來不及開門,狗狗就直接在家裡完事了。如果能讓狗狗吠的時候,狗門自動開啟就太好了。
新增了「吠聲偵測器」
//使用案例:狗門(v3.0)
1. 狗狗想出去
case 1 : (for customer #1&2)
1.1.1. 狗狗吠著要出去
case 1 :
1.1.1.1.1. 主人聽到狗狗在吠
1.1.1.1.2. 主人按下遙控去按鈕
case 2 : (for customer #1 new require)
1.1.1.2.1. 吠聲偵測器「聽見」吠聲
...
6. 狗狗回來
case 1 : (for customer #1)
6.1.1. 很乾淨、吠著要進來
6.1.2. 主人聽到狗狗在吠
case 1 :
6.1.2.1.1. 主人按下遙控器按鈕
case 2 : (for customer #1 new require)
6.1.2.2.1. 吠聲偵測器「聽見」吠聲
...
實際測試後發現,「吠聲偵測器」在真實世界使用上會有個問題,就是其他狗狗的吠聲,也一樣會出發狗門的開啟與關閉,這並不是客戶所希望的,所以我們需要將其升級為「吠聲辨識器」,來正確辨識客戶狗狗的吠聲。
//使用案例:狗門(v3.1)
1. 狗狗想出去
case 1 : (for customer #1&2)
1.1.1. 狗狗吠著要出去
case 1 :
1.1.1.1.1. 主人聽到狗狗在吠
1.1.1.1.2. 主人按下遙控去按鈕
case 2 : (for customer #1 new require)
1.1.1.2.1. 吠聲辨識器「聽見」"主人的狗狗"的吠聲
...
6. 狗狗回來
case 1 : (for customer #1)
6.1.1. 很乾淨、吠著要進來
6.1.2. 主人聽到狗狗在吠
case 1 :
6.1.2.1.1. 主人按下遙控器按鈕
case 2 : (for customer #1 new require)
6.1.2.2.1. 吠聲辨識器「聽見」"主人的狗狗"的吠聲
...
因此,我們需要為「吠聲辨識器」新增使用案例。
//使用案例:吠聲辨識器(v1.0)
1. 主人的狗對著吠聲辨識器吠
2. 吠聲辨識器儲存主人的狗的吠聲
比較底下三人 Randy、Sam 與 Maria 的類別圖設計,看得出其中差異嗎?孰優孰劣呢?
顯而易見的,Sam 設計了 Mark 類別的方式,比 Randy 單純以 string 做比較的設計更符合低耦合的要求,而 Maria 的設計不但保有 Sam 的優點,更符合現實世界的應用,支援了多種吠聲。
所以,孰優孰劣應該已經很明顯了。