您好,登錄后才能下訂單哦!
這篇文章主要介紹“Service和Manager的作用是什么”,在日常操作中,相信很多人在Service和Manager的作用是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Service和Manager的作用是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
說起應用分層,大部分人都會認為這個不是很簡單嘛 就controller,service, mapper三層。看起來簡單,很多人其實并沒有把他們職責劃分開,在很多代碼中,controller做的邏輯比service還多,service往往當成透傳了,這其實是很多人開發代碼都沒有注意到的地方,反正功能也能用,至于放哪無所謂唄。這樣往往造成后面代碼無法復用,層級關系混亂,對后續代碼的維護非常麻煩。
的確在這些人眼中分層只是一個形式,前輩們的代碼這么寫的,其他項目代碼這么寫的,那么我也這么跟著寫。
但是在真正的團隊開發中每個人的習慣都不同,寫出來的代碼必然帶著自己的標簽,有的人習慣controller寫大量的業務邏輯,有的人習慣在service中之間調用遠程服務,這樣就導致了每個人的開發代碼風格完全不同,后續其他人修改的時候,一看,我靠這個人寫的代碼和我平常的習慣完全不同,修改的時候到底是按著自己以前的習慣改,還是跟著前輩們走,這又是個艱難的選擇,選擇一旦有偏差,你的后輩又維護你的代碼的時候,恐怕就要罵人了。
所以一個好的應用分層需要具備以下幾點:
方便后續代碼進行維護擴展;
分層的效果需要讓整個團隊都接受;
各個層職責邊界清晰。
在項目開發中,一個良好的工程架構是必須的。工程架構就像一個骨架,寫代碼就是在這個骨架上增添血肉,這個骨架會影響到整體的模塊劃分,功能劃分,即會影響到代碼的解耦和聚合,將會很大程度上決定一個項目寫得好不好。
這里要分享的是我個人在開發時所采取的工程架構,以及相關的思想。不同的人對于工程架構的理解會不同,實際上也很難分出哪種好,哪種壞,只要符合自己的設計思想,并且能夠有效的進行開發,那就是好的一種架構方式。
如下:
在這里插一嘴哈,在這里我使用的流程圖工具是ProcessOn,是一款在線畫圖工具,非常適合畫各種示意圖,體驗極佳,如果大家想嘗試一下,可以使用我的邀請鏈接注冊(閱讀原文)使用~
接下來將自底向上的講解我對各層的理解和設計,還有我自己所增加的層。
通用工具層其實為對業務無關的,通用的工具類,例如日期處理的工作累,一些數據格式的序列化與反序列化工具。類似于 apache commons 包和 guava 包。
領域模型,也就是我們之前常見的各種數據實體,用 DDD 的術語來說,這種在分層模型中的領域模型稱為貧血領域模型。
貧血領域模型只作為數據載體,只有 getter/setter 方法,而不包含業務方法。
對于分層領域模型,會進一步進行劃分規約,具體如下:
DO(Data Object) : 數據對象,對數據源數據的映射,如數據庫表,ElasticSearch 索引的數據結構。所在包一般命名為 data 。
DTO(Data Transfer Object) : 數據傳輸對象,業務層向外傳輸的對象。如果在某個業務中需要多次查詢獲取不同的數據對象,最后將會把這多個數據對象組合成一個 DTO 并對外傳輸。所在包命名為 dto 。
BO(Business Object) : 業務對象,由 Service 層輸出的封裝業務邏輯的對象。即對象除了數據外,還會包含一定的業務邏輯,也可以說是充血領域模型。但是我一般不會使用。
AO(Application Object) : 應用對象,在 Web 層與 Service 層之間抽象的復用對象模型,極為貼近展示層,復用度不高。比較少用。
VO(View Object) : 顯示層對象,通常是 Web 向模板渲染引擎層傳輸的對象。現在的項目多數為前后端分離,后端只需要返回 JSON ,那么可以理解為 JSON 即是需要渲染成的“模板”。我一般會將這類對象命名為 xxxResponse ,所在包命名為 response 。
Query : 數據查詢對象,數據查詢對象,各層接收上層的查詢請求。其實一般用于 Controller 接受傳過來的參數,可以將其都命名為 xxxQuery ,而我個人習慣將放在 request body 的參數(即 @RequestBody)包裝為 xxxRequest ,而如果使用表單傳輸過來的參數(即 @RequestParam)包裝為 xxxForm ,并分別放在包 request 和包 form 下。
其實貧血領域模型只是作為數據的載體,在一開始我覺得沒必要進行具體的分類,基本上都是往一個包內丟,但是當項目規模上來后,各種各樣的數據實體開始增加,慢慢的變得混亂。對數據對象的分類是為了更好的定義每個數據的作用以及在后續能夠快速的定位到對應的數據對象。
開發中會遇到一些很基礎的,通用的業務邏輯,例如我們可能會根據每個用戶的信息生成一個唯一的 account id 。又或者說有一個用戶排名的需求,我們將從用戶的相關信息中計算出一個分數,從而根據這個分數進行排名。那么這時候我們可能會將這些邏輯寫在 User 數據對象或是其他相應對應的數據對象下。
而我個人來說,不希望數據對象包含業務邏輯,所以我會將這些通用的業務邏輯都抽出來,放到 Manager 中進行統一管理。如會將生成 account id 的邏輯放在 AccountIdGenerator 中,將計算排名分數的邏輯放在 RankCalculator 中。
我將這些類都歸為 Helper ,用于提供底層的業務計算邏輯。而為什么不放在通用工具層中呢?因為這些 Helper 其實都是依賴于特定的領域,即特定的業務。而通用工具類則是業務無關的,任何系統,只要有需要都可以引用。
DAO 就不用過多解釋了,數據訪問對象,用于對數據庫的訪問。但是我個人不會將 DAO 只局限于數據庫,對于不同的數據源的交互,如 HBase ,ElasticSearch ,本地緩存甚至 Redis 我都會定義相對應的 DAO 進行訪問。
這樣的定義,其實是想將數據 CURD 的邏輯和業務邏輯進行分離,將獲 CRUD 封裝在 DAO 中,業務邏輯即放在業務層中。
之前接手了一個項目,項目將 Redis 視為中間件,將相關的邏輯都封裝在 xxxRedisService 中,包括 CRUD 和一些業務邏輯。隨著項目的發展,一些其實可以歸類到一起的業務,變得有些放在了 RedisService 中,一些放在了業務層的 Service 中,可想而知十分混亂,還導致了一些 BUG 的出現。
Service 的作用不用多說明,為具體業務邏輯的封裝層。
具體要說明的是 Manager ,中定義如下:
對第三方平臺封裝的層,預處理返回結果及轉化異常信息
對 Service 層通用能力的下沉,如緩存方案、中間件通用處理
與 DAO 層交互,對多個 DAO 的組合復用
可以將 Manager 理解為對通用邏輯的封裝,避免 Service 與 Service 進行相互調用,以及對通用邏輯的管理。
在開發中,我們經常會遇到 AService 中的某個業務可以提供給 BService 調用,從而讓 BService 調用 AService 的方法,認為是 Service 之間具有共同的業務。其實 Service 之間沒有共同的業務,而是具備通用的邏輯,這時應該將其抽離出來放在 Manager 中。無論何種工程架構都好,我都不贊同 Service 與 Service 之間的相互調用。
在實際開發中,我會對 Manager 進行更細一點的劃分。大致將其分為用于項務類,所封裝的是由 Service 下沉的通用業務。
而另一種則是一些偏向于工具、計算的類,例如某個業務使用了策略模式,所編寫的策略類則屬于這一類。
我會將業務類的用 @Service 注釋,而偏工具類的則用 @Component 注釋。這樣做的原因還是避免業務之間的相互調用,相互耦合。
這里可能會想,為什么不將 Helper 的邏輯也放在 Manager 層中?原因在于 Helper 的邏輯比 Manager 更加基礎,有可能在 DAO 中都會調用 Helper 的相關邏輯,如果放在 Manager 中,就會出現底層依賴上層的問題。
最后的一層,則是暴露給外部調用的層。可以是 Spring 體系中的 Controller ,也可以是 gRPC 。
這一層將組織、調用我們所定義的 Service ,進行業務處理。
無論什么工程架構,都會有其優點以及缺點,在選擇工程架構時,其實就是對優點缺點的衡量。
其實無論什么架構,特別是對業務工程來說,最希望架構帶來的是解耦以及內聚。
通過分層,在一定程度上對項目內的各個模塊進行了解耦內聚,依賴關系十分明確,再怎么寫,只要符合規約,總是上層依賴于下層。而且分層的規約十分簡單,在多人協作的情況下大部分情況都可以很好的遵守規約。
簡單是一個優點,也是一個缺點。分層雖然在一定程度上進行了解耦,但是粒度十分粗,只要不出現下層依賴上層的情況,都可以認為是符合規約的,在這種情況下,很容易導致代碼的分散、功能的碎片化,明明是同一類業務功能的代碼,卻分散在多個類,多個層次之間。在項目不斷迭代時變得巨大時,慢慢就會變得混亂,然后就是一輪重構。
歸根到底就是太松懈了,導致開發人員很容易就是在項目中隨便找個地方寫,還很容易導致由大量的復制粘貼所產生重復代碼。
在學校開設的軟件工程課中,設計一個系統,首先是組織架構的了解,然后從中抽出數據流,然后再在數據流中抽出業務流,進行根據業務流進行開發。而采用分層模型的化,往往在數據流中就可以開始開發,采用分層模型的話,每個業務其實可以簡單的抽象成數據在各層之間的流動。
這可以說是一個優點,簡化了業務的理解,實現快速的開發,我在比較緊的排期下也由這么做過,掃一眼業務,構思好數據流的流動后就動手了。但這也是一個很嚴重的缺點,我見過不少功能性 BUG ,就是由于對業務的不充分理解所導致的,而且由于沒有對業務流程充分理解后就開發,后續的擴展和修復,看起來就是不斷的修修補補。
既然是說工程架構,就不得不提 DDD 這一個概念。
為什么我說的是“與充血領域模型的對比”而不是“與 DDD 的對比”呢?是因為 DDD 是比分層模型更加高層的一種概念,它是一個產品服務,整個團隊開發的一種指導思想,而不是一種工程代碼上的規約。
DDD 可以分為兩大方向,一個是戰略層面上的,即之前提到的是一種開發的指導思想,定義、劃分服務的領域,規定統一語言提高溝通效率等,這也是可以用于使用分層領域模型的項目開發中的。如果要與分層模型對比的話,其實是 DDD 的戰術層面,即充血領域模型。
充血領域模型其實是回歸于面向對象的思想。在目前的分層模型中,哪怕是用 Java 這種面向對象的語言去寫,其實總體上還是一種過程式的編程,在 DDD 中稱為事務腳本。
充血領域模型是重領域,輕 Service 的。以之前生成 account id 以及排名的例子,在充血領域模型中,User 類將會有 generateAccountId 方法和 ranking 方法來完成這一邏輯。
完全的面向對象,就可以充分的發揮面向對象的特性。面向對象的特性在書上為:繼承、多態,封裝。前兩者能夠實現歸一化,使模塊泛化通用,封裝即會使模塊劃分明確,能夠很好的實現解耦和內聚。比起分層模型,使用充血領域模型可以很好的解決上面提到的代碼分散,碎片化的問題。
充血領域模型的優點是面向對象的優點,但是面向對象的缺點也成為這種模型的缺點。首先,萬物皆可抽象在我看來就是偽命題,因為現實世界中總有事務是難以進行抽象的,或者抽象起來不優雅,總是有一種硬是抽象的感覺。
在知乎中有一個很好的回答,描述了面向對象的弊端
相信很多人在初接觸 DDD 時,都會去搜索充血領域模型實踐的例子。其實在學校學習 Java Web 開發時,書本中寫道的 MVC 結構其實在一定程度上也是充血領域模型,Model 除了是數據的載體外,還包含業務邏輯,通過 Controller 對 Model 的選擇以及調用完成業務。假如用這種結構開發,當項目龐大后,我覺得首先遇到的問題應該就是依賴問題,復雜的業務必然牽扯到各方各面,自然也就有復雜的依賴關系產生,甚至會有為了完成業務而產生很“臟”的實現,這是難以避免的。
我個人覺得充血領域模型目前還是只適合于個人,很小的團隊中使用,例如 2 到 3 個人的團隊,因為抽象本身就是一個非常復雜的過程,隨著需求迭代,之前的抽象還不一定正確,如果在較為多人的多人協作中,各種奇奇怪怪的寫法都會出現,必然也會有隨便找個“地”寫的情況出現,這種情況比在分層模型中更為致命。
到此,關于“Service和Manager的作用是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。