1. 程式人生 > >應用程式框架實戰三十五:服務概述

應用程式框架實戰三十五:服務概述

  上一篇介紹了我對幾種實體的認識,本篇將介紹幾種服務的用法。

  預告一下本系列後續計劃,本篇之後,準備進入實戰演練階段,先介紹如何快速解決CRUD操作,從如何使用PD資料建模到使用CodeSmith生成程式碼,先帶你感受一下,再回過來介紹框架內部元素,以免你在閱讀時昏昏欲睡。

應用服務介紹

  對於一個新的設計元素,可以先假定不需要它,等到確實認識到它的作用再引入。那麼,應用服務為我們帶來了哪些好處呢?

應用服務幫助簡化表現層操作

  以MVC為例,如果沒有應用服務,那麼控制器將直接呼叫倉儲,設定查詢條件,轉換DTO等。

  當控制器操作變得複雜,你會想辦法把控制器程式碼分離出去。分離控制器程式碼的最好方法就是建立對應的應用服務

,不要輕易的分離控制器本身,因為這會導致查詢檢視變得困難,並且破壞了約定,導致更高的維護成本。

應用服務為表現層提供唯一的API訪問點

  當一個控制器操作變得複雜時,編寫控制器的程式設計師需要了解更多的知識,這些操作是由哪些聚合、領域服務、基礎設施服務等構造元素組裝起來的呢,呼叫順序如何?

  這是表現層應該關心的問題嗎?

  表現層應該只關心介面展示,這是表現層的基本職責所在,其它職責儘量轉移到後方。

  應用服務將細粒度操作打包為粗粒度操作,讓編寫表現層的程式設計師不再東張西望,他只需要記得一件事:需要訪問任何後端的操作,找應用服務就對了

應用服務為多個表現層減少冗餘程式碼

  如果需要多個表現層,比如需要開發一個WPF程式,功能與MVC完全一樣,這時候,你會發現表現層充斥大量重複程式碼。

  引入應用服務後,表現層程式碼更簡潔,冗餘程式碼更少,建立多個表現層更加輕鬆。

應用服務整合和裝配領域層與基礎設施層

  為了保持領域層的純淨,我們採用依賴倒置原則,領域層只擁有操作介面,具體實現卻在基礎設施層,最終要能執行起來,必須將它們組裝到一起。

  如果沒有應用服務,控制器將需要自己進行裝配,這增加了表現層的負擔,應用服務承接了這項工作,讓表現層專心幹自己的本職工作。

應用服務配合DTO優化遠端呼叫效能

  當採用了分散式架構,為了提升效能,需要儘量減少遠端呼叫次數。        

  應用服務在分散式環境充當了遠端外觀,配合DTO一起解決這個問題。

應用服務與BLL的比較

  對於長時間採用傳統三層架構的朋友,對於應用服務這個構造是無比的親切,初步用起來以後,你發現這個應用服務就是BLL的翻版。

  BLL是傳統三層架構的業務邏輯層,很多人直接用BLL來命名業務邏輯層的服務類,我暫時就用這個稱呼。      

  BLL是業務邏輯放置的場所,BLL將結果儲存到Model實體類中,然後將實體類傳遞給其它層。

  應用服務用於協調領域層與基礎設施層的操作,應用服務本身不應該完成複雜的業務邏輯。

  應用服務與BLL的關鍵區別在於,BLL直接完成業務邏輯,而應用服務會將業務邏輯委託給領域實體或領域服務。

  從程式碼上看,BLL主要通過操作Model的屬性進行業務邏輯的處理,而應用服務通過呼叫領域實體或領域服務的方法完成所有業務操作。        

領域服務介紹

  從前面的介紹,你應該已經發現應用服務是有用的,下面再來看看領域服務。

  在最理想的情況下,所有的業務邏輯都應該高度內聚到聚合中。但對於更復雜的業務,一般都有比較複雜的流程,這些流程上的控制,放入聚合並不合適,因為這些行為不屬於某個聚合。

  如果把這些行為放到應用服務中,可能導致應用服務非常複雜,業務邏輯也從領域層脫離出來,使業務邏輯的管理更加困難。

  為了把業務邏輯重新移回領域層,需要新增一個領域服務。

  現在我們有了應用服務和領域服務兩個構造元素,那麼,對於一個複雜操作,應該將哪一部分放入應用服務,哪些又放到領域服務呢?

  書上介紹,業務邏輯可分為領域邏輯和應用邏輯,領域邏輯應該完全放到領域層,不能洩露到其它層去,而應用邏輯應該放到應用層服務。

  可以看出,說得相當抽象,哪種東西算得上領域邏輯,哪種又是應用邏輯?這個很難精確劃分。

  一個經典的應用邏輯例子是事務控制,事務控制不是客戶的需求,但卻非常重要,所以把這種東西放到應用層,而不是領域層。

  那麼發郵件的操作是領域邏輯,還是應用邏輯??有人說是領域邏輯,有人說是應用邏輯,還有人說要看情況。可謂眾說紛紜,讓你摸不著頭腦。

  不過我們學習的目的不是進行學術辯論,而是切實的提升專案可維護性,所以不用太理會那些考智商的概念,下面談談我的用法。

  對於應用服務,我總是需要它,因為它可以簡化表現層開發。

  對於某些比較簡單的業務邏輯,如果發現建立領域服務並未產生太大價值,我就直接放入應用服務中。比如判斷一個實體的名稱不能重複,這是一個業務需求,首先考慮這個業務邏輯可以放入實體中嗎?不能,因為實體本身無法瞭解自己的名稱有無重複。其次考慮需要建立領域服務嗎?對於這種簡單業務邏輯,建立一個領域服務有點大炮打蚊子的感覺。我會直接將重名檢測放入應用服務中,雖然導致有一點業務邏輯散落到應用層,但我未發現對可維護性造成影響。

  如果業務邏輯比較複雜,我一般會採用TDD方式推進業務開發,這種情況下,建立領域服務是一個極好的選擇,因為領域層依賴低,單元測試更方便

  不論應用服務,還是領域服務,開發的基本原則是,儘量將業務邏輯委託給領域實體,服務僅做排程的工作。

  基礎設施服務比較好理解,就是提供一些基礎支援服務,比如傳送郵件等操作。

需要為服務抽取介面嗎

  學習設計模式時,要求我們面向介面程式設計,但一些物件大師建議不要過度設計,以免導致不必要的複雜性,在《實現領域驅動設計》一書中提出,應用服務使用獨立介面沒有什麼好處。

  雖然介面有不少作用,但一般來講,驅動建立介面的真正需求來自多型。在一般的專案開發中,特別是前期,服務很少具有多型需求,那我們還要不要為服務建立介面?

  在沒有使用Resharper的年代,我使用介面非常小心謹慎,因為從介面定位實現類非常困難,但自從用上了Resharper,介面不再成為障礙。

  另一方面,IOC框架的使用,讓介面的使用進一步普及,我只需要將實現類繫結到介面,在程式中就可以自由使用了。雖然IOC可以直接繫結實現類,但總感覺有點奇怪。

  最後,對於跨層訪問,採用介面互聯也符合分層設計原則。

  對於採用了Ioc框架,並安裝了Resharper這樣強大的工具,介面不會給你造成任何不便,至於是否導致複雜性,則需要自己體會。

  程式碼中採用介面程式設計,可能在大多情況下都未產生實質的好處,但在需求發生變化時,只需修改Ioc配置替換相關實現,這個擴充套件性在不花成本的情況下還是划得來的。

服務命名約定

  當同時需要應用服務和領域服務,會發現服務取名也很困難。比如使用者管理,應用服務叫UserService,如果需要領域服務,也叫UserService就發生衝突 ,但命名為其它可能又不合適。

  我的辦法是應用服務統一以Service結尾,領域服務統一以Manager結尾,這樣就可以簡單的解決這個問題。對於和我一樣的英文菜鳥,可能特別有用。

最新原始碼發放

  本次更新了EasyUi表格列繫結Combox和Combotree的功能。同時新增了一個圖示管理模組,該模組包含對百度WebUploader上傳圖片控制元件的簡單封裝,服務端上傳操作封裝。

  WebUploader控制元件非常給力,且提供的Demo非常好用,我基本直接COPY過來簡單修改就用上了。

  我在Data下載包中提供了一些圖示,以方便大家操作。

  同時,該示例包含了領域服務,並提供了相關的單元測試,大家可以參考。

  下載截幾個執行效果圖。

       

  雖然這個介面包含了樹控制元件的CRUD操作,但總的JS程式碼量還是比較少的。

 

下載時記得推薦

http://files.cnblogs.com/files/xiadao521/Applications.2015.4.9.2.rar

http://files.cnblogs.com/files/xiadao521/Framework.2015.4.8.1.rar

http://files.cnblogs.com/files/xiadao521/Data.2015.4.8.2.rar        

.Net應用程式框架交流QQ群: 386092459,歡迎有興趣的朋友加入討論。

.Net Easyui開發交流QQ群(本群僅限Easyui開發者,非Easyui開發者勿進):157809322

謝謝大家的持續關注,我的部落格地址:http://www.cnblogs.com/xiadao521/