需求描述了軟件系統(tǒng)是什么,架構(gòu)則提供了系統(tǒng)的低成本實(shí)現(xiàn)方案,回答了軟件系統(tǒng)如何做的問(wèn)題。架構(gòu)依賴需求,需求驅(qū)動(dòng)架構(gòu)。
目前,用例是大多數(shù)項(xiàng)目描述需求的方法,軟件分析設(shè)計(jì)活動(dòng)(包括架構(gòu))的輸入就是用例需求規(guī)約或者其衍生品(用戶故事)。作為架構(gòu)或者開(kāi)發(fā)人員,我們需要懂得如何從這些規(guī)約和故事中獲取有用信息,驅(qū)動(dòng)我們的分析設(shè)計(jì)。
這里根據(jù)自己的學(xué)習(xí)理解,結(jié)合以往的實(shí)踐,總結(jié)了幾點(diǎn)如何從用例開(kāi)始架構(gòu)設(shè)計(jì)的方法。
從用例開(kāi)始推導(dǎo)系統(tǒng)結(jié)構(gòu)
系統(tǒng)結(jié)構(gòu)是指系統(tǒng)由哪些組件構(gòu)成,這些組件的職責(zé)以及它們之間的關(guān)系。
系統(tǒng)結(jié)構(gòu)是我們通過(guò)架構(gòu)活動(dòng)創(chuàng)造出來(lái)的,沒(méi)有一個(gè)簡(jiǎn)單、直接、通用的套路得到結(jié)構(gòu)中的組件,但是用例可以啟發(fā)我們的探索。
用例是從用戶和涉眾角度對(duì)系統(tǒng)的描述,它天然就是對(duì)系統(tǒng)的一種劃分:每個(gè)用例代表了系統(tǒng)的一部分需求,代表了涉眾/參與者使用系統(tǒng)的一類場(chǎng)景,從場(chǎng)景的層面看,用例之間沒(méi)有交集。而在用例內(nèi)部,場(chǎng)景、業(yè)務(wù)規(guī)則等元素共同定義了一組強(qiáng)耦合的功能需求。
如果我們繼續(xù)把用例按照參與者進(jìn)行分組,每個(gè)用例組對(duì)應(yīng)一個(gè)或若干個(gè)類似的參與者。由于參與者是業(yè)務(wù)領(lǐng)域中的由人或者其它系統(tǒng)扮演的角色,相似的角色意味著它們提出的功能被組織在一起可能是合理的。
每個(gè)用例組我們引入一個(gè)組件(可能是子系統(tǒng)、也可能是模塊),它們實(shí)現(xiàn)了用例組包含的用例,這些組件構(gòu)成了系統(tǒng)。這個(gè)時(shí)候得到的系統(tǒng)結(jié)構(gòu)實(shí)際上就是所謂的“功能架構(gòu)”,經(jīng)常出現(xiàn)在系統(tǒng)的售前和宣傳文檔中。但是我們要認(rèn)識(shí)到,由于“功能架構(gòu)”沒(méi)有考慮重用和非功能屬性,它不是最終的,可以用于指導(dǎo)開(kāi)發(fā)架構(gòu)。
但是從用例組得到的“功能架構(gòu)”在系統(tǒng)劃分上有一定的合理性,我們把它作為架構(gòu)設(shè)計(jì)的出發(fā)點(diǎn),逐步演進(jìn)。比如:我們選擇一個(gè)功能組件(某個(gè)子系統(tǒng)或者模塊),從對(duì)應(yīng)的用例組中找到若干個(gè)用例,分析它們的功能需求和非功能需求,引入新的組件實(shí)現(xiàn)公共的功能需求;引入新的組件或者精化已有組件實(shí)現(xiàn)非功能需求。
從用例推導(dǎo)領(lǐng)域模型
我之前參加過(guò)UMLChina潘加宇的“軟件方法”培訓(xùn),里面介紹了由用例建模的方法。這里簡(jiǎn)單介紹下。
我們要明確這里的領(lǐng)域模型只描述領(lǐng)域概念,不考慮具體的技術(shù)要素(比如:并發(fā)、事務(wù)等)。
從用例可以推導(dǎo)出邊界類、控制類和多個(gè)實(shí)體類,它們之間的關(guān)系如下:

這些類之間的協(xié)作如下:

為用例定義控制類
一個(gè)用例最多一個(gè)控制類,一個(gè)控制類只關(guān)聯(lián)一個(gè)用例,負(fù)責(zé)接收所在用例對(duì)應(yīng)的業(yè)務(wù)事件,協(xié)調(diào)內(nèi)部的處理。是業(yè)務(wù)用例的調(diào)用入口。
這個(gè)控制類不是必須的,如果發(fā)現(xiàn)不需要協(xié)調(diào),所有邏輯可以由實(shí)體類完成,可以不需要這個(gè)控制類。
從業(yè)務(wù)實(shí)體、業(yè)務(wù)處理功能和業(yè)務(wù)約束條件推導(dǎo)實(shí)體類
用例和實(shí)體類之間是多對(duì)多的關(guān)系。從用例中獲得實(shí)體類的方法這里不展開(kāi)了,直接由業(yè)務(wù)實(shí)體映射可以作為一個(gè)起點(diǎn)。但是要得到高質(zhì)量的領(lǐng)域模型,還需要在這個(gè)基礎(chǔ)上進(jìn)行抽象和挖掘,這個(gè)過(guò)程我總結(jié)不出,不過(guò)這里給大家推薦幾本書(shū):
- 軟件方法(下)(潘加宇)
- 彩色UML建模(Perter Coad)
- Domain driven design(Eric Evans)
另外,還可以參考一下別人在分析和概念層面總結(jié)的領(lǐng)域設(shè)計(jì)模式。
為參與者定義邊界類
邊界類對(duì)應(yīng)用例的參與者。
從我自己的體會(huì)來(lái)看,有必要為每一個(gè)輔助參與者(Supporting Actor)建立一個(gè)邊界類,這個(gè)邊界類的職責(zé)是和系統(tǒng)依賴的外部系統(tǒng)通信,比如:發(fā)送通知、調(diào)用某個(gè)功能等。
對(duì)于主動(dòng)參與者,只有這個(gè)參與者是由時(shí)間系統(tǒng)承擔(dān)的角色時(shí),為這個(gè)角色建立一個(gè)邊界類才是有價(jià)值的。
從用例推導(dǎo)設(shè)計(jì)
當(dāng)我們用具體的語(yǔ)言/框架去實(shí)現(xiàn)之前推導(dǎo)出的領(lǐng)域模型時(shí),必須考慮具體的技術(shù)問(wèn)題,包括:并發(fā)、事務(wù)、性能等,實(shí)際上這些就是用例的質(zhì)量屬性。
如何實(shí)現(xiàn)這些非功能需求呢?肯定有很多方法。我個(gè)人比較傾向于通過(guò)增加一些新的類/組件,在不修改之前的的領(lǐng)域?qū)嶓w類的前提下實(shí)現(xiàn)。實(shí)際上在目前的領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的相關(guān)書(shū)籍里,有很大一部分就是介紹如何在技術(shù)層面實(shí)現(xiàn)領(lǐng)域模型,幫助領(lǐng)域模型落地。
比如:我們要實(shí)現(xiàn)數(shù)據(jù)庫(kù)的訪問(wèn),不是在領(lǐng)域?qū)嶓w類增加類似查詢、保存的方法,而是增加一個(gè)形如:xxxRepository的類。
再比如:某個(gè)功能需要可伸縮,這個(gè)時(shí)候可以在架構(gòu)層面引入新的組件負(fù)責(zé)該功能,組件支持多實(shí)例部署,組件內(nèi)部仍然使用原有的相關(guān)領(lǐng)域模型。