這篇文章是軟件架構(gòu)編年史(譯)的一部分盔夜,這部編年史由一系列關(guān)于軟件架構(gòu)的文章組成怎燥。在這一系列文章中瘫筐,我將寫下我對(duì)軟件架構(gòu)的學(xué)習(xí)和思考,以及我是如何運(yùn)用這些知識(shí)的铐姚。如果你閱讀了這個(gè)系列中之前的文章策肝,本篇文章的的內(nèi)容將更有意義。
EBI 架構(gòu)(Entity-Boundary-Interactor,實(shí)體-邊界-交互器)架構(gòu)因?yàn)?Robert C. Martin 關(guān)于整潔架構(gòu)(我會(huì)在后續(xù)的文章中介紹)的講座而被人熟知驳糯。
然而篇梭,Ivar Jacobson 早在 1992 年就在他的著作 Object-Oriented Software Engineering: A use case driven approach中提出了這個(gè)模式。那時(shí)酝枢,Jacobson 實(shí)際上把它叫做實(shí)體-接口-控制(Entity-Interface-Control)恬偷,但是后來(lái)改成了 EBI,避免“接口”和編程語(yǔ)言中的結(jié)構(gòu)“接口”混淆帘睦,以及“控制”和 MVC 中的控制器混淆袍患。
實(shí)體
實(shí)體對(duì)象承載著系統(tǒng)使用的數(shù)據(jù)與所有和這些數(shù)據(jù)天然耦合在一起的行為。每一個(gè)實(shí)體對(duì)象都代表著一個(gè)和問(wèn)題域相關(guān)的概念竣付,以及它承載的身份和可恢復(fù)的(持久化)數(shù)據(jù)诡延。Jacobson 告訴我們,實(shí)體對(duì)象應(yīng)該包含和對(duì)象自己變同時(shí)發(fā)生變化的邏輯古胆,例如肆良,如果它的數(shù)據(jù)結(jié)構(gòu)發(fā)生變化,這些數(shù)據(jù)上的操作也需要改變逸绎,因此它們也應(yīng)該放在實(shí)體內(nèi)惹恃。
有意思的是,早在 1992 年棺牧,Jacobson 就作出了如下警告:
新手也許有時(shí)會(huì)讓實(shí)體對(duì)象只攜帶數(shù)據(jù)巫糙,把所有動(dòng)態(tài)的行為放到控制對(duì)象中[...]。然而颊乘,這是應(yīng)該避免的参淹。[...] 許多行為反而應(yīng)該放在實(shí)體對(duì)象中》η模——Ivar Jacobson 1992, pp. 134
這就是我們現(xiàn)在所知的“貧血實(shí)體”浙值。
邊界(接口)
邊界對(duì)象是對(duì)系統(tǒng)接口的建模。
[…] 和系統(tǒng)接口有關(guān)的一切都應(yīng)該放在接口對(duì)象中——Ivar Jacobson 1992, pp. 134
所有依賴系統(tǒng)環(huán)境(工具和傳達(dá)機(jī)制)的功能都屬于邊界對(duì)象檩小。
任何角色和系統(tǒng)的交互都要經(jīng)過(guò)邊界對(duì)象开呐。如 Jacobson 所述,角色可以是像客戶或管理員(操作員)這樣的人類用戶识啦,也可以是像告警、打印機(jī)或者第三方 API 這樣的非人類“用戶”神妹。
回味一下邊界的概念颓哮,再看看圖 7.14,把其中的四個(gè)邊界想像成六個(gè)鸵荠,我不禁聯(lián)想到 2005 年才提出的端口和適配器架構(gòu)(我將在后續(xù)的文章中介紹)冕茅,整整晚了 13 年。
交互器(控制)
交互器對(duì)象承載了和其它任何對(duì)象類型天然無(wú)關(guān)的行為。
這些行為通常由對(duì)實(shí)體一些操作組成姨伤,最后將某個(gè)結(jié)果返回給邊界對(duì)象哨坪。
邊界對(duì)象和實(shí)體對(duì)象挑剩下的行為會(huì)被放在控制對(duì)象中≌С—— Ivar Jacobson 1992, pp. 185
這意味著所有不適合放在邊界或?qū)嶓w的行為都會(huì)被放在一個(gè)或多個(gè)控制對(duì)象中当编。
因此,Jacobson 認(rèn)為控制對(duì)象不僅僅是編排用例的對(duì)象徒溪,也包括那些擁有和用例有關(guān)的行為的對(duì)象忿偷,它們既不是邊界也不是實(shí)體。
根據(jù)我的經(jīng)驗(yàn)臊泌,我認(rèn)為他稱為交互器的對(duì)象就是我稱為應(yīng)用服務(wù)(編排用例)和領(lǐng)域服務(wù)(包含領(lǐng)域行為但不是實(shí)體)的對(duì)象鲤桥。
位于中間的交互器對(duì)象地位十分重要,原因在于渠概,如果去掉它們茶凳,特定用例的邏輯就會(huì)被放到實(shí)體中。然而播揪,實(shí)體會(huì)被多個(gè)用例使用贮喧,因此它們會(huì)有通用的用法。特定用例的邏輯如果被放到了實(shí)體中剪芍,就能被多個(gè)邊界使用塞淹,這些邊界最終會(huì)把這個(gè)實(shí)體當(dāng)成通用邏輯。而我們就會(huì)不得不修改這個(gè)實(shí)體讓它適應(yīng)另一個(gè)邊界罪裹,這會(huì)增加實(shí)體的復(fù)雜性而且可能會(huì)破壞用到該實(shí)體的其它用例饱普。
為什么是三種對(duì)象類型?
當(dāng)時(shí)状共,Jacobson 宣稱其它的 OO 方法會(huì)把所有的職責(zé)都放在實(shí)體本身套耕,但是他(和他的支持者)則傾向與將這些職責(zé)分散到三種對(duì)象類型中,因?yàn)檫@樣能讓系統(tǒng)更適應(yīng)變化峡继。
[…] 所有的系統(tǒng)都會(huì)發(fā)生變化冯袍。因此,只有所有的變化都發(fā)生在局部碾牌,穩(wěn)定性才會(huì)存在康愤,也就是說(shuō),變化最好只能影響系統(tǒng)中的一個(gè)對(duì)象舶吗≌骼洌—— Ivar Jacobson 1992, pg. 135
通過(guò)職責(zé)的封裝將系統(tǒng)的變化控制在局部,就是 EBI 架構(gòu)的目標(biāo)誓琼。我們仔細(xì)思考一下检激,Jacobson 只是沒(méi)有直接說(shuō)出十年之后由 Robert C. Martin 在他的 “Agile Software Development, Principles, Patterns, and Practices”一書中提出的單一職責(zé)原則罷了肴捉。
總結(jié)
和 MVC 模式中的 Model 代表著整個(gè)后端(包括所有實(shí)體、服務(wù)和它們之間的關(guān)系在內(nèi)的一切)一樣叔收,EBI 模式將邊界看作是和外部世界的完整連接齿穗,而不僅僅是一個(gè)視圖、一個(gè)控制器或是一個(gè)接口(這里指的是編程語(yǔ)言結(jié)構(gòu)的接口)饺律。 邊界代表了對(duì)應(yīng)著 MVC 中的 View 和 Controller 的整個(gè)展現(xiàn)層窃页。EBI 中的實(shí)體代表了承載著數(shù)據(jù)及其行為的真正實(shí)體,而交互器對(duì)象代表了展現(xiàn)層和實(shí)體之間的連接蓝晒,也就是我所謂的應(yīng)用服務(wù)和領(lǐng)域服務(wù)腮出。
EBI 模式關(guān)注后端而 MVC 更關(guān)注前端。它們不能互相取代芝薇,它們是對(duì)方的補(bǔ)充胚嘲。如果把它們放在一個(gè)模式中,我們可以把它叫做視圖-控制器-交互器-實(shí)體 (View-Controller-Interactor-Entity)洛二。
引用來(lái)源
1992 – Ivar Jacobson – Object-Oriented Software Engineering: A use case driven approach
2002 – Robert C. Martin – Agile Software Development, Principles, Patterns, and Practices
2002 – Robert C. Martin – Single Responsibility Principle
Eclipse Process Framework – Entity-Control-Boundary Pattern
Jon Pearce – Implementing Use Cases
2012 – Robert C. Martin – Clean Architecture (NDC 2012)
2014 – Adam Bien – How to tackle JEE
2014 – Ali Parvini – Model View Controller vs Boundary Control Entity