這篇文章主要講解了“基于領(lǐng)域分析web設(shè)計(jì)的架構(gòu)規(guī)范”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“基于領(lǐng)域分析web設(shè)計(jì)的架構(gòu)規(guī)范”吧!
創(chuàng)新互聯(lián)建站是專業(yè)的個(gè)舊網(wǎng)站建設(shè)公司,個(gè)舊接單;提供成都網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì),網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行個(gè)舊網(wǎng)站開發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!
基于上面提到的讀寫隔離的思想,那么我們可以很清楚地看到上面這種情況可以看到:
查詢業(yè)務(wù),從入口層(如Controller),調(diào)用Finder
,而Finder
調(diào)用Repository
(具體實(shí)現(xiàn)如Hiberante,Mybatis等等均可),這一條線下來(lái),我們?nèi)徊挥每紤]這個(gè)系統(tǒng)的增刪改就是如何做的,就像他們完全處于不同的空間一樣,互不干涉,互不影響,甚至,永遠(yuǎn)互不相見。 某種程度上來(lái)說(shuō),這種這種架構(gòu)追求的效果,一種美感。
所以,接下來(lái),我們關(guān)注的,就是增刪改這一部分了,也就是命令操作是開始要扎扎實(shí)實(shí)地來(lái)對(duì)這個(gè)系統(tǒng)進(jìn)行修改了
首先讓我們把視野抬高一些,從整個(gè)項(xiàng)目產(chǎn)品的上空來(lái)看看
除開少數(shù)非常扁平的純技術(shù)服務(wù)項(xiàng)目(比如AI識(shí)別,文本分析等等),其他絕大部分企業(yè)項(xiàng)目都有其核心的商業(yè)邏輯,而這些邏輯,往往也會(huì)以核心的領(lǐng)域概念來(lái)提現(xiàn),從簡(jiǎn)單粗暴一點(diǎn)角度映射到設(shè)計(jì)開發(fā)中,那就是類class
電商系統(tǒng),核心領(lǐng)域至少有【商品】,【訂單】,【用戶】,【物流】等;
SNS社交平臺(tái),至少有【用戶】,【博文/帖子】,【私信】,【通知】等;
進(jìn)銷存系統(tǒng),至少有【賬戶】,【角色/權(quán)限】,【商品】,【客戶/供應(yīng)商】等;
在線教育平臺(tái),至少有【用戶】,【課程】,【訂單】等;
而這其中,也有主次,大家可以回頭看看自己所開發(fā)過(guò)的項(xiàng)目。 但凡是有狀態(tài)字段的類,很大可能都是整個(gè)項(xiàng)目的核心領(lǐng)域之一。 其實(shí)很好理解,因?yàn)樗辛鞒?,因?yàn)樗枰桓黝惒僮鱽?lái)變更它的狀態(tài),所以,他很可能貫穿了這個(gè)項(xiàng)目中某一個(gè)關(guān)鍵商業(yè)邏輯,比如電商系統(tǒng)中,
【訂單】肯定有狀態(tài),從[待支付]-[已支付]-[派送中]-[已收貨](méi),甚至還有[已取消],[退款中],[退款失敗],[退款成功],腦補(bǔ)一下,就知道會(huì)生成多少?gòu)?fù)雜的業(yè)務(wù)流程了
【用戶】一般來(lái)說(shuō)也會(huì)有狀態(tài),比如[正常],[凍結(jié)],但是可以想到,如果某個(gè)系統(tǒng)沒(méi)有這方面權(quán)限與安全的要求,【用戶】也可能就沒(méi)有狀態(tài)了,那么自然也不會(huì)有對(duì)應(yīng)的操作對(duì)其進(jìn)行修改,可能只會(huì)有創(chuàng)建
所以,如果在這些系統(tǒng)的早期設(shè)計(jì)階段,要我選擇一個(gè)最重要的UML圖,我會(huì)選擇狀態(tài)圖,以下就是整個(gè)系統(tǒng)中最核心的訂單狀態(tài)圖
可以看到,把握一個(gè)核心領(lǐng)域的狀態(tài)變更,自然而然就能歸納出來(lái)很大一部分系統(tǒng)的功能需求。我們?cè)谶@里看到,這些所有箭頭所觸發(fā)的動(dòng)作,其實(shí)都是命令,也其實(shí)都是會(huì)落地到各個(gè)相關(guān)領(lǐng)域的增刪改上。
當(dāng)然這里還是一個(gè)粗粒度的表示,無(wú)法單單依據(jù)這個(gè)就馬上落地開發(fā),因?yàn)榧词姑恳粋€(gè)箭頭所代表的功能都可以寫出一個(gè)完整甚至很復(fù)雜的用例。但至少這是一個(gè)非常清晰的引導(dǎo)。
我們目前所用的Spring體系,幾乎都是貧血模型,也就是說(shuō),真正的實(shí)體類里,都只有各個(gè)屬性的Get與Set方法。 而假如我們要進(jìn)行一個(gè)操作,訂單取消
,那么最常見的做法是什么?
//一個(gè)大而全的訂單服務(wù)類 public class OrderService{ public void cancelOrder(Long orderId){ Order order = orderRepository.getById(orderId); order.setStatus(OrderStatus.CANCELLED); //省略,其他屬性的操作... } } //然后在上層(如Controller層)中這么調(diào)用 orderService.cancelOrder(10086);
這是目前行業(yè)中非常流行的做法,也是Spring的IOC機(jī)制天然形成的做法————盡可能的無(wú)狀態(tài)化。這種做法,在業(yè)務(wù)迭代時(shí)對(duì)代碼的變動(dòng)評(píng)判標(biāo)準(zhǔn)相對(duì)簡(jiǎn)單,都往Service里放就行了,然后實(shí)體對(duì)象只需要GetSet即可,簡(jiǎn)單粗暴,非常容易上手,也正是這種特性,讓這種編碼風(fēng)格廣為流傳。
以上這些話沒(méi)有任何貶義,因?yàn)槿魏问虑?,存在即合理,我所?jīng)歷的公司項(xiàng)目,幾乎都是這樣做的,大家合作起來(lái)沒(méi)多大問(wèn)題,業(yè)務(wù)也都還跑得不錯(cuò)。
那為什么我還想去做一些改變呢?
因?yàn)槲矣X得我們需要再重新審視一下實(shí)體Entity
實(shí)體為什么要有主鍵? 因?yàn)闆](méi)有主鍵,那我們?cè)趺粗罆r(shí)要查詢/修改哪條數(shù)據(jù)呢?
這個(gè)回答沒(méi)有問(wèn)題,只是這句話里其實(shí)還蘊(yùn)藏更深的含義
這個(gè)實(shí)體是一個(gè)真實(shí)存在的東西(對(duì),哪怕它看不見摸不著,但也是存在的),而且會(huì)以一種形態(tài)被“存儲(chǔ)/持久化”在一個(gè)存儲(chǔ)介質(zhì)里,比如說(shuō)數(shù)據(jù)庫(kù);
當(dāng)我們需要對(duì)某個(gè)實(shí)體進(jìn)行操作時(shí),我們需要通過(guò)一種手段將它“加載/讀取/獲得”出來(lái),就像你取快遞時(shí),快遞員根據(jù)你提供的編號(hào),從包裹里把那個(gè)東西取出來(lái),完全一樣;
取出來(lái)了怎么辦?那自然就是要對(duì)它進(jìn)行操作了。沒(méi)錯(cuò),這個(gè)操作,就是對(duì)我們找出來(lái)的實(shí)體進(jìn)行操作,而不是別的東西。
所以,從“拿取”,到“操作”,這兩步,一切順理成章,行云流水,所以,以領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的做法,或者說(shuō),充血模型的做法,會(huì)是這樣:
//應(yīng)用層入口類,這里以Controller為例 public class OrderController{ @PostMapping("/cancel") @Transactional public ActionResponse cancelOrder(@RequestBody CancelOrderRequest request){ //拿?。焊鶕?jù)標(biāo)識(shí)符定位到我們要操作的實(shí)體 Order order = orderRepository.getById(request.getOrderId()); //操作:對(duì),沒(méi)錯(cuò),說(shuō)的就是你 order,就是對(duì)你,進(jìn)行操作,不是別人! order.cancel(); //返回結(jié)果 return ActionResponse.ok(); } } //真正的業(yè)務(wù)邏輯,就是在Order實(shí)體里 @Entity public class Order{ private OrderStatus status; private String customerName; //... public void cancel(){ //變更狀態(tài) status = OrderStatus.CANCELLED; //一些其他屬性變動(dòng),略 } }
好,依舊有不少值得探討的地方:
我們這里直接在Controller中就開啟了Transactional,可能看起來(lái)有點(diǎn)反常規(guī),但我個(gè)人覺得沒(méi)什么問(wèn)題,除了有點(diǎn)不習(xí)慣,仔細(xì)想想,本身都只不過(guò)是Spring的一種組件而已
所以如果你用的諸如Hibernate之類的JDBC框架,可以無(wú)需再進(jìn)行多余的類似save操作,這也更好的提現(xiàn)了領(lǐng)域設(shè)計(jì)的思想,因?yàn)檫@時(shí),這個(gè)order就是一個(gè)實(shí)實(shí)在在被我們找出來(lái)的實(shí)體,對(duì)它的改動(dòng),自動(dòng)映射到底層持久化,很自然,也必然。
最更容易引發(fā)槽點(diǎn)的地方,就是order.cancel()
,也就是充血模型的精髓,將行為定位到一個(gè)實(shí)體類上,而不是不加思考地直接扔進(jìn)OrderService
里。
業(yè)界一直有一種非?!懊烂睢钡卣f(shuō)法,曾經(jīng)我一度非常向往,就是“讓代碼成詩(shī)”。 換句話說(shuō),就是既然追求可讀性,那么我們要盡可能的讓代碼天然具有一種“主謂賓”的感覺,就拿上面“取消訂單”做比方,我們是否會(huì)覺得:
訂單好端端的在那里放著,它自己又不能對(duì)自己做什么,自然應(yīng)該“別人”對(duì)他進(jìn)行了操作: OrderService.cancel(orderId); 某某某 取消了 這個(gè)訂單 Perfect! 這樣讀起來(lái),才非常通順,可讀性才更好!
我曾經(jīng)也是這種風(fēng)格死忠,而Spring廣為流傳的無(wú)狀態(tài)架構(gòu)模式也將這種風(fēng)格發(fā)揚(yáng)光大。 只是我現(xiàn)在,在經(jīng)歷了越來(lái)越多復(fù)雜業(yè)務(wù),長(zhǎng)事務(wù)的開發(fā)需求后,越來(lái)越覺得,這個(gè)還有有些硬傷
如果一定要讀得通暢,更應(yīng)該是someOperator.cancel(orderId)
即某個(gè)操作人取消了訂單,而不是OrderService
,誰(shuí)都知道OrderService
就是一個(gè)無(wú)狀態(tài)的代碼大集合,一個(gè)冰冷的代碼而已。但顯然someOperator.cancel(orderId)
這種做法也是更加不可能實(shí)現(xiàn)的,原因就不用過(guò)多解釋了。
order.cancel()
,只有2個(gè)部分,{操作目標(biāo)是誰(shuí)}.{做了什么事情}
,清晰明了,言簡(jiǎn)意賅。我相信絕大多數(shù)人的閱讀習(xí)慣也都是從左往右,那么視線第一下掃到的目標(biāo)一定是最左邊的執(zhí)行對(duì)象,也就是order
,那么可以在第一時(shí)間明確,這個(gè)行為是發(fā)生在誰(shuí)身上,而如果是orderService.cancel(orderId)
,無(wú)形中,orderService
是一個(gè)占據(jù)了視線最有力位置的一個(gè)巨大的噪點(diǎn)——因?yàn)樗鼪](méi)有任何的業(yè)務(wù)意義,你要看的,反而是后面的方法和參數(shù),這在閱讀上百行甚至幾百行的復(fù)合長(zhǎng)業(yè)務(wù)的時(shí)候,你會(huì)很快困頓,迷失方向。
感謝各位的閱讀,以上就是“基于領(lǐng)域分析web設(shè)計(jì)的架構(gòu)規(guī)范”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)基于領(lǐng)域分析web設(shè)計(jì)的架構(gòu)規(guī)范這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!