模型驅(qū)動設(shè)計(MDD)之靈活設(shè)計

字號:

靈活設(shè)計可以使我們隨著項目開發(fā)的進(jìn)行,感到速度越來越快,而不是越來越慢,甚至 停滯不前。靈活設(shè)計是對領(lǐng)域建模的補(bǔ)充,當(dāng)我們從領(lǐng)域中抓住那些隱隱約約的線索和概念原型后,就象準(zhǔn)備好原料;下面就是通過迭代將原料錘煉成一定具體的形狀,可以俗稱“打鐵”,那么打鐵打到什么形狀算可以了呢? 也就是最終希望達(dá)到什么樣的設(shè)計呢?
    有些軟件打著“靈活性”旗號,卻出現(xiàn)很多多余的抽象和間接層次,從而導(dǎo)致了復(fù)雜性,靈活性可能導(dǎo)致復(fù)雜性, 但是靈活性不是導(dǎo)致復(fù)雜性的必然原因,如何將靈活性的發(fā)展通往簡單,其中精湛技巧就需要學(xué)習(xí)和不斷實踐, 正確的理論指導(dǎo)是必不可少的,模型驅(qū)動設(shè)計(MDD)提供這樣一個科學(xué)的方法論。
    在Eric Evans的“領(lǐng)域驅(qū)動設(shè)計”一書中專門探討了這樣提供靈活設(shè)計的模式和方法,下面簡要述說如下:
    明顯意圖的接口
    接口的名稱必須表達(dá)明顯意圖,而不是模棱兩可,接口雖然是抽象,但是也不能抽象到別人不知你所云, 如果其他開發(fā)人員必須查看接口的實現(xiàn)子類才能搞清楚你這個接口的意圖,那么你的接口抽象無疑是失敗的,
    使用明顯意圖的接口可以將整個子領(lǐng)域切分成一個個單獨模塊,每個模塊使用帶有明顯意圖的接口封裝起來, 這種切割方式用來調(diào)整項目的焦點和對付大型系統(tǒng)的復(fù)雜性。
    如果僅僅有大型系統(tǒng)開發(fā)經(jīng)驗,但是沒有大型系統(tǒng)的分割經(jīng)驗,更重要的是良好設(shè)計理論基礎(chǔ),那些大型 系統(tǒng)開發(fā)經(jīng)驗也只是如過眼煙云,不會在你的程序生涯中占據(jù)多大的重要位置。
    下面我們聚焦被劃分成單個模塊的內(nèi)部設(shè)計模式:
    邊界影響
    在軟件中,操作分為:命令和查詢,命令就是能夠使 系統(tǒng)狀態(tài)發(fā)生改變的操作,如增刪改等操作。這些操作都可能需要有副功能,如希望增刪改完成后還要返回一些結(jié)果,這些主要功能之外的副業(yè),也稱為邊界影響(side effect)。一些傳統(tǒng)過程經(jīng)驗的程序員經(jīng)常喜歡搞“一機(jī)多用”,喜歡將很多功能揉合在一起。
    大多數(shù)操作會調(diào)用其他操作,造成任意深度的嵌套,這樣形成一個樹形結(jié)構(gòu)的調(diào)用關(guān)系,這就容易使我們很難 預(yù)測調(diào)用一個操作會產(chǎn)生什么樣的結(jié)果,調(diào)用一個操作變得謹(jǐn)慎,甚至戰(zhàn)戰(zhàn)兢兢,雖然Ioc或DI container使 得這種嵌套關(guān)系的管理變得容易,但是不能保證每個操作本身的設(shè)計能降低復(fù)雜性,后者就是我們現(xiàn)在關(guān)注的。
    為什么我們調(diào)用一個操作時會變得小心,因為這個操作設(shè)計時可能不執(zhí)行主要功能,還有其他副功能,這些 副功能可以認(rèn)為是一種多余副作用,解決辦法很簡單:設(shè)計這個操作時消滅副作用;如果不能消滅,就將其 分離顯式分離并單獨表達(dá)出來。
    所以,我們設(shè)計增刪改命令和查詢功能時,盡可能分離它們到不同操作中實現(xiàn),不要在增刪改命令執(zhí)行的同時 返回任何領(lǐng)域數(shù)據(jù)。
    如果邊界影響不能通過設(shè)計避免,那么我們就直面它,在增刪改等命令執(zhí)行同時返回數(shù)據(jù),當(dāng)這樣做的同時, 我們就使用斷言assertion來約束我們這樣的設(shè)計,通過斷言能夠易于使用單元測試Junit等工具測試。從而 保證你的命令簡單有規(guī)則。
    總之還是那句有些哲學(xué)意義的話:對于邊界功能,首先要去除它,如果不能回避它,就承認(rèn)它,但是同時會約束它。
    邊界影響主要的是Service接口怎么做的問題。在實際項目中,Model和Service是相互結(jié)合不斷重構(gòu)的。那么Model和Service粒度是如何界定的?