這篇文章主要介紹“Service和Manager的作用是什么”,在日常操作中,相信很多人在Service和Manager的作用是什么問題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”Service和Manager的作用是什么”的疑惑有所幫助!接下來,請(qǐng)跟著小編一起來學(xué)習(xí)吧!
成都創(chuàng)新互聯(lián)主要為客戶提供服務(wù)項(xiàng)目涵蓋了網(wǎng)頁(yè)視覺設(shè)計(jì)、VI標(biāo)志設(shè)計(jì)、成都全網(wǎng)營(yíng)銷推廣、網(wǎng)站程序開發(fā)、HTML5響應(yīng)式成都網(wǎng)站建設(shè)、手機(jī)網(wǎng)站開發(fā)、微商城、網(wǎng)站托管及成都網(wǎng)站維護(hù)、WEB系統(tǒng)開發(fā)、域名注冊(cè)、國(guó)內(nèi)外服務(wù)器租用、視頻、平面設(shè)計(jì)、SEO優(yōu)化排名。設(shè)計(jì)、前端、后端三個(gè)建站步驟的完善服務(wù)體系。一人跟蹤測(cè)試的建站服務(wù)標(biāo)準(zhǔn)。已經(jīng)為成都輕質(zhì)隔墻板行業(yè)客戶提供了網(wǎng)站營(yíng)銷服務(wù)。
說起應(yīng)用分層,大部分人都會(huì)認(rèn)為這個(gè)不是很簡(jiǎn)單嘛 就controller,service, mapper三層??雌饋砗?jiǎn)單,很多人其實(shí)并沒有把他們職責(zé)劃分開,在很多代碼中,controller做的邏輯比service還多,service往往當(dāng)成透?jìng)髁?,這其實(shí)是很多人開發(fā)代碼都沒有注意到的地方,反正功能也能用,至于放哪無所謂唄。這樣往往造成后面代碼無法復(fù)用,層級(jí)關(guān)系混亂,對(duì)后續(xù)代碼的維護(hù)非常麻煩。
的確在這些人眼中分層只是一個(gè)形式,前輩們的代碼這么寫的,其他項(xiàng)目代碼這么寫的,那么我也這么跟著寫。
但是在真正的團(tuán)隊(duì)開發(fā)中每個(gè)人的習(xí)慣都不同,寫出來的代碼必然帶著自己的標(biāo)簽,有的人習(xí)慣controller寫大量的業(yè)務(wù)邏輯,有的人習(xí)慣在service中之間調(diào)用遠(yuǎn)程服務(wù),這樣就導(dǎo)致了每個(gè)人的開發(fā)代碼風(fēng)格完全不同,后續(xù)其他人修改的時(shí)候,一看,我靠這個(gè)人寫的代碼和我平常的習(xí)慣完全不同,修改的時(shí)候到底是按著自己以前的習(xí)慣改,還是跟著前輩們走,這又是個(gè)艱難的選擇,選擇一旦有偏差,你的后輩又維護(hù)你的代碼的時(shí)候,恐怕就要罵人了。
所以一個(gè)好的應(yīng)用分層需要具備以下幾點(diǎn):
方便后續(xù)代碼進(jìn)行維護(hù)擴(kuò)展;
分層的效果需要讓整個(gè)團(tuán)隊(duì)都接受;
各個(gè)層職責(zé)邊界清晰。
在項(xiàng)目開發(fā)中,一個(gè)良好的工程架構(gòu)是必須的。工程架構(gòu)就像一個(gè)骨架,寫代碼就是在這個(gè)骨架上增添血肉,這個(gè)骨架會(huì)影響到整體的模塊劃分,功能劃分,即會(huì)影響到代碼的解耦和聚合,將會(huì)很大程度上決定一個(gè)項(xiàng)目寫得好不好。
這里要分享的是我個(gè)人在開發(fā)時(shí)所采取的工程架構(gòu),以及相關(guān)的思想。不同的人對(duì)于工程架構(gòu)的理解會(huì)不同,實(shí)際上也很難分出哪種好,哪種壞,只要符合自己的設(shè)計(jì)思想,并且能夠有效的進(jìn)行開發(fā),那就是好的一種架構(gòu)方式。
如下:
在這里插一嘴哈,在這里我使用的流程圖工具是ProcessOn,是一款在線畫圖工具,非常適合畫各種示意圖,體驗(yàn)極佳,如果大家想嘗試一下,可以使用我的邀請(qǐng)鏈接注冊(cè)(閱讀原文)使用~
接下來將自底向上的講解我對(duì)各層的理解和設(shè)計(jì),還有我自己所增加的層。
通用工具層其實(shí)為對(duì)業(yè)務(wù)無關(guān)的,通用的工具類,例如日期處理的工作累,一些數(shù)據(jù)格式的序列化與反序列化工具。類似于 apache commons 包和 guava 包。
領(lǐng)域模型,也就是我們之前常見的各種數(shù)據(jù)實(shí)體,用 DDD 的術(shù)語來說,這種在分層模型中的領(lǐng)域模型稱為貧血領(lǐng)域模型。
貧血領(lǐng)域模型只作為數(shù)據(jù)載體,只有 getter/setter 方法,而不包含業(yè)務(wù)方法。
對(duì)于分層領(lǐng)域模型,會(huì)進(jìn)一步進(jìn)行劃分規(guī)約,具體如下:
DO(Data Object): 數(shù)據(jù)對(duì)象,對(duì)數(shù)據(jù)源數(shù)據(jù)的映射,如數(shù)據(jù)庫(kù)表,ElasticSearch 索引的數(shù)據(jù)結(jié)構(gòu)。所在包一般命名為 data 。
DTO(Data Transfer Object): 數(shù)據(jù)傳輸對(duì)象,業(yè)務(wù)層向外傳輸?shù)膶?duì)象。如果在某個(gè)業(yè)務(wù)中需要多次查詢獲取不同的數(shù)據(jù)對(duì)象,最后將會(huì)把這多個(gè)數(shù)據(jù)對(duì)象組合成一個(gè) DTO 并對(duì)外傳輸。所在包命名為 dto 。
BO(Business Object): 業(yè)務(wù)對(duì)象,由 Service 層輸出的封裝業(yè)務(wù)邏輯的對(duì)象。即對(duì)象除了數(shù)據(jù)外,還會(huì)包含一定的業(yè)務(wù)邏輯,也可以說是充血領(lǐng)域模型。但是我一般不會(huì)使用。
AO(Application Object): 應(yīng)用對(duì)象,在 Web 層與 Service 層之間抽象的復(fù)用對(duì)象模型,極為貼近展示層,復(fù)用度不高。比較少用。
VO(View Object): 顯示層對(duì)象,通常是 Web 向模板渲染引擎層傳輸?shù)膶?duì)象?,F(xiàn)在的項(xiàng)目多數(shù)為前后端分離,后端只需要返回 JSON ,那么可以理解為 JSON 即是需要渲染成的“模板”。我一般會(huì)將這類對(duì)象命名為 xxxResponse ,所在包命名為 response 。
Query: 數(shù)據(jù)查詢對(duì)象,數(shù)據(jù)查詢對(duì)象,各層接收上層的查詢請(qǐng)求。其實(shí)一般用于 Controller 接受傳過來的參數(shù),可以將其都命名為 xxxQuery ,而我個(gè)人習(xí)慣將放在 request body 的參數(shù)(即 @RequestBody)包裝為 xxxRequest ,而如果使用表單傳輸過來的參數(shù)(即 @RequestParam)包裝為 xxxForm ,并分別放在包 request 和包 form 下。
其實(shí)貧血領(lǐng)域模型只是作為數(shù)據(jù)的載體,在一開始我覺得沒必要進(jìn)行具體的分類,基本上都是往一個(gè)包內(nèi)丟,但是當(dāng)項(xiàng)目規(guī)模上來后,各種各樣的數(shù)據(jù)實(shí)體開始增加,慢慢的變得混亂。對(duì)數(shù)據(jù)對(duì)象的分類是為了更好的定義每個(gè)數(shù)據(jù)的作用以及在后續(xù)能夠快速的定位到對(duì)應(yīng)的數(shù)據(jù)對(duì)象。
開發(fā)中會(huì)遇到一些很基礎(chǔ)的,通用的業(yè)務(wù)邏輯,例如我們可能會(huì)根據(jù)每個(gè)用戶的信息生成一個(gè)唯一的 account id 。又或者說有一個(gè)用戶排名的需求,我們將從用戶的相關(guān)信息中計(jì)算出一個(gè)分?jǐn)?shù),從而根據(jù)這個(gè)分?jǐn)?shù)進(jìn)行排名。那么這時(shí)候我們可能會(huì)將這些邏輯寫在 User 數(shù)據(jù)對(duì)象或是其他相應(yīng)對(duì)應(yīng)的數(shù)據(jù)對(duì)象下。
而我個(gè)人來說,不希望數(shù)據(jù)對(duì)象包含業(yè)務(wù)邏輯,所以我會(huì)將這些通用的業(yè)務(wù)邏輯都抽出來,放到 Manager 中進(jìn)行統(tǒng)一管理。如會(huì)將生成 account id 的邏輯放在 AccountIdGenerator 中,將計(jì)算排名分?jǐn)?shù)的邏輯放在 RankCalculator 中。
我將這些類都?xì)w為 Helper ,用于提供底層的業(yè)務(wù)計(jì)算邏輯。而為什么不放在通用工具層中呢?因?yàn)檫@些 Helper 其實(shí)都是依賴于特定的領(lǐng)域,即特定的業(yè)務(wù)。而通用工具類則是業(yè)務(wù)無關(guān)的,任何系統(tǒng),只要有需要都可以引用。
DAO 就不用過多解釋了,數(shù)據(jù)訪問對(duì)象,用于對(duì)數(shù)據(jù)庫(kù)的訪問。但是我個(gè)人不會(huì)將 DAO 只局限于數(shù)據(jù)庫(kù),對(duì)于不同的數(shù)據(jù)源的交互,如 HBase ,ElasticSearch ,本地緩存甚至 redis 我都會(huì)定義相對(duì)應(yīng)的 DAO 進(jìn)行訪問。
這樣的定義,其實(shí)是想將數(shù)據(jù) CURD 的邏輯和業(yè)務(wù)邏輯進(jìn)行分離,將獲 CRUD 封裝在 DAO 中,業(yè)務(wù)邏輯即放在業(yè)務(wù)層中。
之前接手了一個(gè)項(xiàng)目,項(xiàng)目將 Redis 視為中間件,將相關(guān)的邏輯都封裝在 xxxRedisService 中,包括 CRUD 和一些業(yè)務(wù)邏輯。隨著項(xiàng)目的發(fā)展,一些其實(shí)可以歸類到一起的業(yè)務(wù),變得有些放在了 RedisService 中,一些放在了業(yè)務(wù)層的 Service 中,可想而知十分混亂,還導(dǎo)致了一些 BUG 的出現(xiàn)。
Service 的作用不用多說明,為具體業(yè)務(wù)邏輯的封裝層。
具體要說明的是 Manager ,中定義如下:
對(duì)第三方平臺(tái)封裝的層,預(yù)處理返回結(jié)果及轉(zhuǎn)化異常信息
對(duì) Service 層通用能力的下沉,如緩存方案、中間件通用處理
與 DAO 層交互,對(duì)多個(gè) DAO 的組合復(fù)用
可以將 Manager 理解為對(duì)通用邏輯的封裝,避免 Service 與 Service 進(jìn)行相互調(diào)用,以及對(duì)通用邏輯的管理。
在開發(fā)中,我們經(jīng)常會(huì)遇到 AService 中的某個(gè)業(yè)務(wù)可以提供給 BService 調(diào)用,從而讓 BService 調(diào)用 AService 的方法,認(rèn)為是 Service 之間具有共同的業(yè)務(wù)。其實(shí) Service 之間沒有共同的業(yè)務(wù),而是具備通用的邏輯,這時(shí)應(yīng)該將其抽離出來放在 Manager 中。無論何種工程架構(gòu)都好,我都不贊同 Service 與 Service 之間的相互調(diào)用。
在實(shí)際開發(fā)中,我會(huì)對(duì) Manager 進(jìn)行更細(xì)一點(diǎn)的劃分。大致將其分為用于項(xiàng)務(wù)類,所封裝的是由 Service 下沉的通用業(yè)務(wù)。
而另一種則是一些偏向于工具、計(jì)算的類,例如某個(gè)業(yè)務(wù)使用了策略模式,所編寫的策略類則屬于這一類。
我會(huì)將業(yè)務(wù)類的用 @Service 注釋,而偏工具類的則用 @Component 注釋。這樣做的原因還是避免業(yè)務(wù)之間的相互調(diào)用,相互耦合。
這里可能會(huì)想,為什么不將 Helper 的邏輯也放在 Manager 層中?原因在于 Helper 的邏輯比 Manager 更加基礎(chǔ),有可能在 DAO 中都會(huì)調(diào)用 Helper 的相關(guān)邏輯,如果放在 Manager 中,就會(huì)出現(xiàn)底層依賴上層的問題。
最后的一層,則是暴露給外部調(diào)用的層??梢允?Spring 體系中的 Controller ,也可以是 gRPC 。
這一層將組織、調(diào)用我們所定義的 Service ,進(jìn)行業(yè)務(wù)處理。
無論什么工程架構(gòu),都會(huì)有其優(yōu)點(diǎn)以及缺點(diǎn),在選擇工程架構(gòu)時(shí),其實(shí)就是對(duì)優(yōu)點(diǎn)缺點(diǎn)的衡量。
其實(shí)無論什么架構(gòu),特別是對(duì)業(yè)務(wù)工程來說,最希望架構(gòu)帶來的是解耦以及內(nèi)聚。
通過分層,在一定程度上對(duì)項(xiàng)目?jī)?nèi)的各個(gè)模塊進(jìn)行了解耦內(nèi)聚,依賴關(guān)系十分明確,再怎么寫,只要符合規(guī)約,總是上層依賴于下層。而且分層的規(guī)約十分簡(jiǎn)單,在多人協(xié)作的情況下大部分情況都可以很好的遵守規(guī)約。
簡(jiǎn)單是一個(gè)優(yōu)點(diǎn),也是一個(gè)缺點(diǎn)。分層雖然在一定程度上進(jìn)行了解耦,但是粒度十分粗,只要不出現(xiàn)下層依賴上層的情況,都可以認(rèn)為是符合規(guī)約的,在這種情況下,很容易導(dǎo)致代碼的分散、功能的碎片化,明明是同一類業(yè)務(wù)功能的代碼,卻分散在多個(gè)類,多個(gè)層次之間。在項(xiàng)目不斷迭代時(shí)變得巨大時(shí),慢慢就會(huì)變得混亂,然后就是一輪重構(gòu)。
歸根到底就是太松懈了,導(dǎo)致開發(fā)人員很容易就是在項(xiàng)目中隨便找個(gè)地方寫,還很容易導(dǎo)致由大量的復(fù)制粘貼所產(chǎn)生重復(fù)代碼。
在學(xué)校開設(shè)的軟件工程課中,設(shè)計(jì)一個(gè)系統(tǒng),首先是組織架構(gòu)的了解,然后從中抽出數(shù)據(jù)流,然后再在數(shù)據(jù)流中抽出業(yè)務(wù)流,進(jìn)行根據(jù)業(yè)務(wù)流進(jìn)行開發(fā)。而采用分層模型的化,往往在數(shù)據(jù)流中就可以開始開發(fā),采用分層模型的話,每個(gè)業(yè)務(wù)其實(shí)可以簡(jiǎn)單的抽象成數(shù)據(jù)在各層之間的流動(dòng)。
這可以說是一個(gè)優(yōu)點(diǎn),簡(jiǎn)化了業(yè)務(wù)的理解,實(shí)現(xiàn)快速的開發(fā),我在比較緊的排期下也由這么做過,掃一眼業(yè)務(wù),構(gòu)思好數(shù)據(jù)流的流動(dòng)后就動(dòng)手了。但這也是一個(gè)很嚴(yán)重的缺點(diǎn),我見過不少功能性 BUG ,就是由于對(duì)業(yè)務(wù)的不充分理解所導(dǎo)致的,而且由于沒有對(duì)業(yè)務(wù)流程充分理解后就開發(fā),后續(xù)的擴(kuò)展和修復(fù),看起來就是不斷的修修補(bǔ)補(bǔ)。
既然是說工程架構(gòu),就不得不提 DDD 這一個(gè)概念。
為什么我說的是“與充血領(lǐng)域模型的對(duì)比”而不是“與 DDD 的對(duì)比”呢?是因?yàn)?DDD 是比分層模型更加高層的一種概念,它是一個(gè)產(chǎn)品服務(wù),整個(gè)團(tuán)隊(duì)開發(fā)的一種指導(dǎo)思想,而不是一種工程代碼上的規(guī)約。
DDD 可以分為兩大方向,一個(gè)是戰(zhàn)略層面上的,即之前提到的是一種開發(fā)的指導(dǎo)思想,定義、劃分服務(wù)的領(lǐng)域,規(guī)定統(tǒng)一語言提高溝通效率等,這也是可以用于使用分層領(lǐng)域模型的項(xiàng)目開發(fā)中的。如果要與分層模型對(duì)比的話,其實(shí)是 DDD 的戰(zhàn)術(shù)層面,即充血領(lǐng)域模型。
充血領(lǐng)域模型其實(shí)是回歸于面向?qū)ο蟮乃枷?。在目前的分層模型中,哪怕是?Java 這種面向?qū)ο蟮恼Z言去寫,其實(shí)總體上還是一種過程式的編程,在 DDD 中稱為事務(wù)腳本。
充血領(lǐng)域模型是重領(lǐng)域,輕 Service 的。以之前生成 account id 以及排名的例子,在充血領(lǐng)域模型中,User 類將會(huì)有 generateAccountId 方法和 ranking 方法來完成這一邏輯。
完全的面向?qū)ο?,就可以充分的發(fā)揮面向?qū)ο蟮奶匦?。面向?qū)ο蟮奶匦栽跁蠟椋?em>繼承、多態(tài),封裝。前兩者能夠?qū)崿F(xiàn)歸一化,使模塊泛化通用,封裝即會(huì)使模塊劃分明確,能夠很好的實(shí)現(xiàn)解耦和內(nèi)聚。比起分層模型,使用充血領(lǐng)域模型可以很好的解決上面提到的代碼分散,碎片化的問題。
充血領(lǐng)域模型的優(yōu)點(diǎn)是面向?qū)ο蟮膬?yōu)點(diǎn),但是面向?qū)ο蟮娜秉c(diǎn)也成為這種模型的缺點(diǎn)。首先,萬物皆可抽象在我看來就是偽命題,因?yàn)楝F(xiàn)實(shí)世界中總有事務(wù)是難以進(jìn)行抽象的,或者抽象起來不優(yōu)雅,總是有一種硬是抽象的感覺。
在知乎中有一個(gè)很好的回答,描述了面向?qū)ο蟮谋锥?/p>
相信很多人在初接觸 DDD 時(shí),都會(huì)去搜索充血領(lǐng)域模型實(shí)踐的例子。其實(shí)在學(xué)校學(xué)習(xí) Java Web 開發(fā)時(shí),書本中寫道的 MVC 結(jié)構(gòu)其實(shí)在一定程度上也是充血領(lǐng)域模型,Model 除了是數(shù)據(jù)的載體外,還包含業(yè)務(wù)邏輯,通過 Controller 對(duì) Model 的選擇以及調(diào)用完成業(yè)務(wù)。假如用這種結(jié)構(gòu)開發(fā),當(dāng)項(xiàng)目龐大后,我覺得首先遇到的問題應(yīng)該就是依賴問題,復(fù)雜的業(yè)務(wù)必然牽扯到各方各面,自然也就有復(fù)雜的依賴關(guān)系產(chǎn)生,甚至?xí)袨榱送瓿蓸I(yè)務(wù)而產(chǎn)生很“臟”的實(shí)現(xiàn),這是難以避免的。
我個(gè)人覺得充血領(lǐng)域模型目前還是只適合于個(gè)人,很小的團(tuán)隊(duì)中使用,例如 2 到 3 個(gè)人的團(tuán)隊(duì),因?yàn)槌橄蟊旧砭褪且粋€(gè)非常復(fù)雜的過程,隨著需求迭代,之前的抽象還不一定正確,如果在較為多人的多人協(xié)作中,各種奇奇怪怪的寫法都會(huì)出現(xiàn),必然也會(huì)有隨便找個(gè)“地”寫的情況出現(xiàn),這種情況比在分層模型中更為致命。
到此,關(guān)于“Service和Manager的作用是什么”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!