第8章 分析 之 分析類圖
牆上挂了根長藤,長藤上面挂銅鈴
《長藤挂銅鈴》;詞:元庸,曲:梅翁,唱:逸敏
公衆号文章最長隻能20000字,本文更全的連結請見:
http://www.umlchina.com/book/softmeth_08.htm
8.1.5 識别分析類和屬性
目前已有的工件是用例規約,它可以作為識别類的開始。閱讀用例規約的基本路徑、擴充路徑、字段清單和業務規則部分,針對表示名詞或事件的詞彙,逐個思考,這是不是系統要記住的概念?如果是,那麼它是類,還是某個類的屬性?
圖8-21 從用例規約提煉類和屬性
★之前做需求啟發時,如果為了整理領域知識畫了類圖,在此處可以挑系統相關的部分,結合用例規約的内容精化。
如果您有關系資料庫模組化的經驗,也可以這樣思考:如果系統采用關系資料庫來儲存資料,那麼資料庫裡應該會有哪些表?這樣思考得到的表和實體類基本上是一一映射的。表對應類,列對應屬性,行對應對象,關系對應關聯。如果資料模組化技能掌握得好,得到的資料模型符合1NF、2NF和3NF,那麼用資料模組化的思考方式得到的類圖極有可能也是合格的。反過來也可以說,如果類模組化做得好,映射得到的關系資料庫模型也會有合理的結構。
當然,我們畫類圖的目的不僅是為了得到資料庫,面向對象和資料庫也沒有必然的綁定關系。任何系統都可以用面向對象的方式來構造,不管它用什麼方式來持久存儲對象。
例如,我們坐電梯上樓,進電梯門,按了按鈕5。電梯到了5層,會把門打開。電梯肯定記住了某些東西才能這麼做,它記住了什麼?可以認為它記住了一個整數5,代碼會這樣寫:
int destinationFloor=5;
但是,這樣的做法,背後的類型是int,這是基礎設施領域的概念,不是電梯排程領域的概念,說明我們的複用級别是基于基礎設施域,沒有基于核心域。圖8-22表達了電梯排程系統的恰當抽象。
圖8-22 核心域概念
圖8-22中的規律隻和核心域(電梯排程領域)有關,和如何用非核心域映射無關。一部電梯去往多個目标樓層,這"多個目标樓層"在電梯對象裡如何表示?用數組?清單?集合?不影響核心域的概念。
接下來将從《軟體方法(上)》給出的UMLChina系統兩個用例的用例規約提煉類。為了友善提煉,我把需要考慮的文字加了下劃線,逐一分析。
用例編号:UC1
用例名:發送公開課通知
執行者:時間(主)、UMLChina助理(輔)、軟體開發人員(輔)
……
基本路徑:
1. 當到達時間周期時,系統選擇下一個适合發郵件的發件郵箱以及下一個待發往的郵箱位址
2. 系統生成電子郵件
3. 系統使用所選發件郵箱向所選待發往的郵箱位址發送電子郵件
4. 系統記錄郵件發送情況
擴充路徑:
1a. 沒有正在生效的通知任務:
1a1. 用例結束
1b. 有正在生效的通知任務,但沒有指定發件郵箱:
1b1. 系統向UMLChina助理的電子郵箱位址發郵件告知正在生效的通知任務沒有指定發件郵箱
1b2. 用例結束
1c. 有正在生效的通知任務,有指定發件郵箱,但沒有适合發郵件的發件郵箱:
1c1. 用例結束
1d. 沒有下一個待發往的郵箱位址:
1d1. 系統結束正在生效的通知任務
1d2. 系統向UMLChina助理的電子郵箱位址發郵件告知正在生效的通知任務已結束
1d3. 用例結束
字段清單:
2. 電子郵件=主題+内容
2. 郵件主題的模闆:
[聯系人稱呼]您好,歡迎您參加[公開課舉辦城市][公開課開始日期]-[公開課結束日期]的[公開課主題]公開課
2.郵件内容的模闆:
[聯系人稱呼]您好,
歡迎您參加[公開課舉辦城市][公開課開始日期]-[公開課結束日期]的[公開課主題]公開課
開課時間: [公開課開始日期]-[公開課結束日期]([周*、周*])(9:00-12:00,13:10-17:10)
上課地點: [公開課舉辦城市]
費用:每人[公開課費用]元,含午餐。交通、住宿費請自理。
[報名交費資訊]
[公開課大綱]
3. 需要用到的資訊:發件郵箱SMTP伺服器位址、發件郵箱賬戶名、發件郵箱密碼
4. 郵件發送情況=郵箱位址+發送時間+發件郵箱+是否成功
業務規則:
1. 時間周期預設為5秒
1. 定位适合發郵件的發件郵箱的規則:從正在生效的通知任務指定的發件郵箱中找出以下值最大而且值大于0的郵箱: (目前時間-郵箱上次發送時間)-郵箱最小發件時間間隔
1. 定位下一個待發往的郵箱位址的規則:針對正在生效的通知任務,随機選取符合以下條件的郵箱位址:聯系人符合公開課通知任務條件,而且聯系人有郵箱位址尚未被正在生效的通知任務通知
1. 聯系人符合公開課通知任務條件的規則:聯系人目前所在城市所屬分區與公開課舉辦城市所屬分區相同,而且聯系人不屬于"拒絕公開課通知聯系人",而且聯系人不屬于該公開課"已通知聯系人",而且聯系人目前所在組織不屬于該公開課"已通知的組織"
********************************** 背景知識: 為了盡可能減少幹擾,通知的總原則是:能不通知就不通知。 如果某位軟體開發人員已經表明不想接到公開課通知,就不應再發公開課通知郵件給他,該人員成為"拒絕公開課通知聯系人";如果某位軟體開發人員已經在QQ、微信等其他途徑咨詢過某次公開課,也不應再發該次公開課的郵件給他,該人員成為該次公開課"已通知聯系人";如果某組織的上司(例如研發總監、教育訓練經理……)已經詢問過某次公開課事宜,就不必再通知該組織裡的開發人員該次公開課的資訊,該組織成為該次公開課"已通知的組織"。 可以推測系統可能有另外的一個或多個用例會修改這些資訊,但這些問題留到後面再考慮。 ********************************** |
用例編号:UC2
用例名:建立公開課通知任務
執行者: UMLChina助理
……
基本路徑:
1. UMLChina助理選擇公開課,請求建立通知任務
2. 系統驗證所選公開課适合建立通知任務
3. 系統回報設定通知任務界面
4. UMLChina助理送出公開課通知任務
5. 系統回報公開課通知任務
6. UMLChina助理确認
7. 系統儲存通知任務
8. 系統回報已經建立通知任務
擴充路徑:
2a. 所選公開課已存在正在生效的通知任務:
2a1. 系統回報所選公開課已存在正在生效的通知任務,詢問是否停止所選公開課正在生效的通知任務
2a2. UMLChina助理選擇停止所選公開課正在生效的通知任務
2a2a.選擇不停止:
2a2a1. UMLChina助理選擇不停止所選公開課正在生效的通知任務
2a2a2. 用例結束
2a3. 系統停止所選公開課正在生效的通知任務
2a4. 傳回3
字段清單:
4. 通知任務=公開課+{發件郵箱}*+{已通知的組織}*+{已通知的聯系人}*+是否立即生效
7. 通知任務=4+建立時間+建立人
業務規則:
2. 公開課适合建立通知任務的規則:該公開課沒有正在生效的通知任務,而且公開課的開始日期應該是目前日期的3天或更長時間之後
接下來,我們來抽絲剝繭,逐句分析用例規約。
1. 當到達時間周期①時,系統②選擇下一個适合發郵件的發件郵箱③以及下一個待發往的郵箱位址④
1. 時間周期預設為5秒⑤
1. 定位适合發郵件的發件郵箱的規則:從正在生效的通知任務⑥指定的發件郵箱⑦中找出以下值最大而且值大于0的郵箱: (目前時間-郵箱上次發送時間⑧)-郵箱最小發件時間間隔⑨
1. 定位下一個待發往的郵箱位址的規則:針對正在生效的通知任務,随機選取符合以下條件的郵箱位址:聯系人⑩符合公開課⑪通知任務條件,而且聯系人有郵箱位址尚未被正在生效的通知任務通知。
1. 聯系人符合公開課通知任務條件的規則:聯系人目前所在城市⑫所屬分區⑬與公開課舉辦城市⑭所屬分區相同,而且聯系人不屬于"拒絕公開課通知聯系人"⑮,而且聯系人不屬于該公開課"已通知聯系人"⑯,而且聯系人目前所在組織⑰不屬于該公開課"已通知的組織"⑱。
①時間周期。這是執行用例"發送公開課通知"的時間周期,可以看作和時間互動的邊界類的一個屬性。
圖8-23 UMLChina系統類圖1
②系統。在分析工作流中,"系統"的概念已經被打碎成各個類,是以"系統"這個詞不需要識别成類。
有些開發人員在這裡會犯錯誤,把"系統"識别成一個類,畫成這樣:
圖8-24 無意義的類圖
這個圖隻是簡單功能分解的另一個變體,對剖析系統的複雜性沒有幫助,卻給開發人員帶來一種虛假的成就感:我描述了幾個類之間的關系,而且還是組合關系,已經開始剖析系統的複雜性了呢!
"系統"的概念是需求工作流的概念。在需求工作流,我們把系統看作一個整體對外提供服務。
工作流 | 如何稱呼目前要開發的系統 | 原因 |
業務模組化 | 某某系統 | 研究對象是組織,組織中有很多系統,需要指出系統的名字。 |
需求 | 系統 | 研究對象是目前要開發的系統,不需要再說名字。 |
分析 | 很多個類 | 研究焦點進入系統的内部,思考系統内部的構成。 |
圖8-25 如何稱呼目前要開發的系統
③下一個适合發郵件的發件郵箱。"發件郵箱"映射為類。"下一個适合發郵件",映射為類的狀态屬性,深入模組化後,再消除這些狀态屬性。
圖8-26 UMLChina系統類圖2
④下一個待發往的郵箱位址。"郵箱位址"本來應該是"聯系人"的一個屬性,但"下一個待發往的"這個定語說明"郵箱位址"有"下一個待發往"這樣的狀态屬性,另外考慮到聯系人會有多個不同用途的郵箱位址,是以把"郵箱位址"獨立出來變成一個類,"下一個待發往"作為"郵箱位址"的狀态屬性。
圖8-27 UMLChina系統類圖3
⑤時間周期預設為5秒。映射為"時間周期"屬性的預設值。
圖8-28 UMLChina系統類圖4
為了防止濫發郵件,郵箱提供商會規定每個郵箱每天發送郵件總量以及發送時間間隔,如果違反規定,郵件會暫時無法發出,郵箱甚至會被關閉。過于頻繁地檢測是否有符合條件的發件郵箱,沒有意義,但如果檢測時間間隔太長,導緻可以發郵件時發件郵箱卻空置,也影響發郵件的效率。5秒應該是合理的值。
⑥正在生效的通知任務。"通知任務"映射為類,"正在生效"映射為狀态屬性。
圖8-29 UMLChina系統類圖5
⑦指定的發件郵箱。"通知任務"關聯到"發件郵箱",同時調整一下類的位置。
圖8-30 UMLChina系統類圖6
⑧上次發送時間。"發件郵箱"的屬性。
⑨最小發件時間間隔。"發件郵箱"的屬性。
圖8-31 UMLChina系統類圖7
⑩聯系人。映射為類。
⑪公開課。映射為類。
圖8-32 UMLChina系統類圖8
再根據"聯系人符合公開課通知任務條件,而且聯系人有郵箱位址尚未被正在生效的通知任務通知。"建立關聯。
圖8-33 UMLChina系統類圖9
⑫聯系人目前所在城市。"城市"映射為類,和"聯系人"建立關聯。"目前所在城市"是關聯中"城市"的角色名稱。
⑬所屬分區。"分區"映射為類,和"城市"建立關聯。
⑭公開課舉辦城市。"公開課"和"城市"建立關聯,"舉辦城市"是關聯中"城市"的角色名稱。
圖8-34 UMLChina系統類圖10
⑮"拒絕公開課通知聯系人"。"拒絕公開課通知"映射為"聯系人"的一個狀态屬性。
⑯該公開課"已通知聯系人"。在"聯系人"和"公開課"中間再加一個名稱為"通知"的關聯。深入模組化後,會慢慢精簡這些關聯。
圖8-35 UMLChina系統類圖11
⑰聯系人目前所在組織。"組織"映射為類,和"聯系人"建立關聯。"目前所在組織"是關聯中"組織"的角色名稱。
⑱該公開課"已通知的組織"。在"組織"和"公開課"中間再加一個名稱為"通知"的關聯。
這時,類圖上的類已經比較多了,我們調整類圖中各個類的位置,讓關聯線盡可能不交叉。
圖8-36 UMLChina系統類圖12
2. 系統生成電子郵件⑲
字段清單:
2. 電子郵件=主題+内容⑳
2. 郵件主題的模闆:
[聯系人稱呼
]您好,歡迎您參加[公開課舉辦城市][公開課開始日期
]-[公開課結束日期
]的[公開課主題
]公開課
2.郵件内容的模闆:
[聯系人稱呼]您好,
歡迎您參加[公開課舉辦城市][公開課開始日期]-[公開課結束日期]的[公開課主題]公開課
開課時間: [公開課開始日期]-[公開課結束日期]([周*、周*])(9:00-12:00,13:10-17:10)
上課地點: [公開課舉辦城市]
費用:每人[公開課費用
]元,含午餐。交通、住宿費請自理。
[報名交費資訊
]
[公開課大綱
]
⑲電子郵件。"電子郵件"映射為類。
⑳主題+内容。"主題"、"内容"映射為"電子郵件"的屬性。
圖8-37 UMLChina系統類圖13
聯系人稱呼。"稱呼"映射為"聯系人"的屬性。
公開課開始日期。"開始日期"映射為"公開課"的屬性。
公開課結束日期。"結束日期"映射為"公開課"的屬性。
公開課主題。"主題"映射為"公開課"的屬性。
公開課費用。"費用"映射為"公開課"的屬性。
報名交費資訊。"報名交費資訊"映射為"公開課"的屬性。
公開課大綱。"大綱"映射為"公開課"的屬性。
圖8-38 UMLChina系統類圖14
3. 系統使用所選發件郵箱向所選待發往的郵箱位址發送電子郵件
3. 需要用到的資訊:發件郵箱SMTP伺服器位址
、發件郵箱賬戶名
、發件郵箱密碼
使用所選發件郵箱向所選待發往的郵箱位址發送電子郵件。在"電子郵件"和"發件郵箱"、 "電子郵件"和"郵箱位址"之間建立關聯。
SMTP伺服器位址。"SMTP伺服器位址"映射為"發件郵箱"的屬性。
發件郵箱賬戶名。"賬戶名"映射為"發件郵箱"的屬性。
發件郵箱密碼。"密碼"映射為"發件郵箱"的屬性。
圖8-39 UMLChina系統類圖15
4. 系統記錄郵件發送情況
4. 郵件發送情況=郵箱位址+發送時間+發件郵箱+是否成功
系統記錄郵件發送情況。"郵件發送"映射為類,和"電子郵件"關聯。
郵件發送情況=郵箱位址+發送時間+發件郵箱+是否成功。将"發件郵箱"和"電子郵件"之間的"使用"關聯改為"發件郵箱"和"郵件發送"之間的"使用"關聯。"時間"和"成功"映射為"郵件發送"的屬性。
一封電子郵件如果發送失敗,可以再次發送,使用的發件郵箱可以是之前的發送用過的發件郵箱,也可以是新的郵箱。也就是說,同一封電子郵件直到發送成功為止可能會發生多次發送事件,關聯到哪個發件郵箱是由各次發送事件決定的。電子郵件發往哪個郵箱位址,隻和電子郵件有關。
圖8-40 UMLChina系統類圖16
1a. 沒有正在生效的通知任務:
1a1. 用例結束
1b. 有正在生效的通知任務,但沒有指定發件郵箱:
1b1. 系統向UMLChina助理的電子郵箱位址
發郵件告知正在生效的通知任務沒有指定發件郵箱
1b2. 用例結束
1c. 有正在生效的通知任務,有指定發件郵箱,但沒有适合發郵件的發件郵箱:
1c1. 用例結束
1d. 沒有下一個待發往的郵箱位址:
1d1. 系統結束正在生效的通知任務
1d2. 系統向UMLChina助理的電子郵箱位址發郵件告知正在生效的通知任務已結束
1d3. 用例結束
UMLChina助理的電子郵箱位址。"助理"映射成類,關聯到"郵箱位址"。這樣做并不是很妥當,公開課郵件不需要發往助理的郵箱位址,聯系人的郵箱位址需要懂得的屬性它不需要知道,例如"下一個待發往"、"公開課已通知",但此處先暫時放下,後面再一起精化。
通知任務已結束。"已結束"映射為"通知任務"的狀态屬性。
圖8-41 UMLChina系統類圖17
第一個用例分析完畢,接下來看第二個用例。
1. UMLChina助理
選擇公開課,請求建立通知任務
UMLChina助理。UMLChina助理是系統執行者,首先映射一個邊界類"助理接口"。
圖8-42 UMLChina系統類圖18
有的模組化人員在這兒會犯錯誤,直接映射一個"助理"類。系統執行者和實體類沒有必然的對應關系。
例如,乘客坐電梯上樓,乘客是電梯系統的執行者,但電梯系統可能不需要"乘客"實體類,因為它不需要記住乘客的資訊。當然,有朝一日,電梯更新為維穩電梯,用例規約裡有:
乘客提供身份辨別
系統驗證身份辨別合法
系統記錄乘客資訊和入廂時間
這時,電梯系統裡就有"乘客"實體類了,因為系統要記住乘客的資訊。某個概念是否映射實體類的依據是系統是否要記住它,和是否有同名的執行者無關。
和執行者對應的是邊界類。電梯系統沒有"乘客"類,但會有"乘客接口"類,目前的實作形式多為圖8-43所示。
圖8-43 乘客接口的虛與實
2. 系統驗證所選公開課适合建立通知任務
業務規則:
2. 公開課适合建立通知任務的規則:該公開課沒有正在生效的通知任務
,而且公開課的開始日期應該是目前日期
的3天或更長時間之後。
該公開課沒有正在生效的通知任務。在"公開課"和"通知任務"之間建立關聯。
目前日期。和本領域沒有特定關系,不識别。
圖8-44 UMLChina系統類圖19
7. 系統儲存通知任務
字段清單:
7. 通知任務=4+建立時間+建立人
通知任務=4+建立時間+建立人。"建立時間"映射為"通知任務"的屬性。在"通知任務"和"助理"之間建立關聯,"助理"的角色為"建立人"。
圖8-45 UMLChina系統類圖20
至此,用例規約裡的概念已經提煉完畢。接下來的工作就是通過審查類和屬性來進一步精化類圖,但是在此之前,我們來看看識别類和屬性時的一些要點。
8.1.6 識别分析類和屬性的要點
8.1.6.1 關于中英文命名
該用中文就用中文,該用英文就用英文,該用日文就用日文。中英文命名問題和設計工作流(編碼、設計資料庫……)中碰到的問題是類似的。分析類雖然不包含設計工作流的知識,但它是設計工作流的基礎。反對在設計工作流中使用中文命名(類名、屬性名、表名、字段名……)的理由可能是編譯器不支援、DBMS不支援、切換輸入法太麻煩、版式不好看等。編譯器、DBMS因素随着時代的發展慢慢地不再是問題,版式、切換輸入法問題在畫圖模組化中不存在,是以用中文名稱不是大問題。當然,如果開發團隊是國際化的,就是另外一種情況。
總之,分析類和屬性(包括後面要添加的操作)的名稱應該時以友善開發團隊思考和交流領域知識為首要考慮因素。
EA提供了别名(Alias)。名稱可以用英文——其實不是英文,是編譯器廣泛支援的符号集合。除名稱外,再加一個别名用于顯示。不過,建議暫時不用。如果熟悉的領域詞彙是中文名,在那時還需要花時間去想一個英文名,分散了模組化中思考的精力,更不用說模糊的漢語拼音和錯誤的英文會給後續工作帶來的麻煩了。
8.1.6.2 命名中不帶備援詞彙
不要在類名的最後加"類"字;
不要在類名的前後加"Class"或"C";
不要在類名的最後加"情況"、"資訊"、"記錄"、"資料"、"表"、"庫"、"單"等詞。
圖8-46 類名後面不需要加備援詞
如果系統關注的焦點是"資料處理",處理的資料是什麼内容無所謂,"資訊"、"資料"也可以作為一個類的名稱,但它和"人員"不屬于一個領域,不在一個抽象級别。如圖8-47。
圖8-47 "資訊"作為類
當然,如果一個帶有以上字尾的詞在領域中已經存在很久,成為了領域的術語,直接使用無妨。例如"訂單"帶有"單"字,實際上描述的是一次"購買",但"訂單"已經在領域中廣泛使用,可以作為類名。
屬性名稱前不需要加類名。
如圖8-48。按"類的屬性"念出來,"人員的姓名"很好,"人員的人員姓名"備援了。
圖8-48 屬性名稱前不需要加類名
英文名用單數。
如圖8-49。"顧客"的執行個體是一名顧客,"顧客們"的執行個體是什麼?一個集合?
設計工作流中的資料庫表名也應該用單數。有一些開發人員習慣在最後加s(當然,複數未必是加s),甚至有一些架構直接就在表名後面加上s,理由是表裡有很多行。這個問題和上面提到的類名稱後面加個"類"字是一樣的,都是一種備援。"類"、"表"的概念已經隐含了"多個對象"、"多行"的意思。說"我是一個類,我的名字叫顧客"就夠了,不需要說"我是一個類,我的名字叫顧客類"或者"我是一個表,我的名字叫顧客們"。
圖8-49 英文名用單數
8.1.6.3 命名要一緻
同一個概念要用一緻的詞彙表達。例如"寶貝"還是"商品"?"顧客"、"客戶"還是"會員"?如果沒有差别,應該統一到同一個詞彙,如果有差别,應該在類圖上表達其中差别。如果還沒有思考到如何在類圖上表達,可以先在類的說明中闡述确切含義。
如圖8-50,左側的幾個概念中,"寶貝"和"商品"、"顧客"和"客戶"含義相同,把它們合并,同時在類圖上更精細地表達"使用者"、"顧客"、"會員"概念之間的差别。
8-50 理清混淆的概念
[1] 《軟體方法》上冊第六章已讨論過開發人員話語中“技術”一詞的狹隘。
[2]當然,可以以Office為開發工具做二次開發,但此時使用的系統已經不是Office而是核心域的應用系統。
[3] ( a、b、c都大于
時成立)
[4] C#有一種實作套路是直接寫Property,後文再評述這樣的實作。
[5]有人提出一種改進的腦補方法——結對腦補,美其名曰“結對程式設計”。