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