算上實習的公司,如今是第四家公司了。頭兩家公司是傳統行業,用的也是經典的三層架構,action,service,Dao。dao層負責持久化;service層負責業務邏輯,事務處理;action負責接收參數和返回數據。我相信只要是java程序員都這樣玩過。也曾經疑惑過,爲何要一個簡單的CRUD也要還要整倆接口。java
還有一個問題是,咱們一般會定義的一個實體類和數據庫徹底匹配,特別是用mybatis的時候,可是當咱們返回前臺的結果極可能和數據庫不同,這個時候可能須要定義額外的實體類用於匹配查詢結果,曾經爲了圖方便,還用map玩過。程序員
帶着這些疑惑稀裏糊塗的待了兩家公司,終於來到了互聯網公司。redis
一樣仍是針對一個表的CRUD,尼瑪,分了四層,定義了四個實體類,當時我震驚了。後來有人告訴從格局上講這是SOA、模塊化思想,從接口來講,這是領域設計思想。固然架構上除了傳統的struts二、spring、mybatis還有dubbo、zookeeper、redis等spring
我花了一段時間來體會這種架構,簡單的說下吧。sql
若是是對UI顯示,層次是這樣滴, action , application service,domain service,dao。數據庫
若是是對外暴露(dubbo接口),export,application service,domain service,dao。緩存
實體類分爲,DTO,DO,VO還有Query(也至關於DTO)mybatis
當時項目對application service層簡稱 ao 層,對domain service層簡稱manager 層架構
dao層的做用,你們都知道;manager層用做處理當前領域的業務,它多是單表,也多是多表,一般就是當前項目所牽扯的主業務表的增刪改查。ao 層就是跨領域層屬於應用層,一般須要調其它服務的接口,action層就是接收參數和返回結果,沒有任何邏輯。app
而後實體類,DO是和數據庫相匹配的實體,VO是和前臺列表相匹配的實體,DTO是接口傳輸的實體,Query是接口查詢條件的實體。
當時作的是CRM系統,我主要參與的就是商家、合同相關的業務。由於當時這個項目,是公司第一個模塊化思想的項目,雖然不難作的也很頭疼。
以合同查詢來講吧,若是是PC端和手機端來調用的話,入口就是action,傳遞的參數會包裝成Query。由於合同存有城市、商圈、店鋪等id、還有附屬協議等信息。最開始我直接是一個關聯查詢,直接通用mybatis匹配成VO,返回到前臺。
被個人技術負責人給批了,正確的作法是這樣的,我從數據庫查出來的數據是個純淨的DO,這個DO通過service(當時咱們是想在這一層用redis作緩存)到ao層,在ao層他會根據城市、商圈、店鋪等id分別調不一樣的接口去查詢相應的信息,而後在組裝成VO,返回到action層。
由於當時對服務化這種思想不理解,以爲一條SQL就能解決的問題結果工做量瞬間陡增,還讓我鬱悶好久。
當有其餘內部應用要調用這個接口,這個時候走的就是dubbo接口了,經過export接收參數,參數仍是query,若是隻是查詢單獨的合同信息,export會調用service,而後在export層將service返回的DO轉成Dto。 若是須要經過這個接口查詢合同的關聯信息,好比店鋪,商家,就調用AO層,
而後將AO層返回的對象轉成DTO。
在DO轉VO,或者DO轉DTO的時候,一般是在VO、DTO定義一個靜態工廠方法,經過該方法轉換,保證業務代碼的純淨。
這就是一個簡單的查詢接口,雖然開始以爲有些繞,後來也以爲蠻好,也接觸了SOA和領域設計這種思想。這家公司待了沒多久,公司C輪融資失敗,爲了緩解公司的經濟危機,我也就跳槽了。而後我就來了這一家公司,一家C輪的電商公司。
仍是SOA的思想,項目包結構依然分四層,export,facade,service,dao。實體類就定義了比較隨意了,沒有嚴格的規範。開始我以爲這四層跟我上家公司應該相似,只是名字換了而已。結果開發項目的時候卻發現不同,也讓我對這種分層有了更深的認識。
export層:dubbo暴露的接口,實際功能基本上就是對應app的一個按鈕。主要是作異常歸集和接口暴露。
facade層:至關於一個門面,接口的主流程,理論上就是一條線,比較乾淨,拋一個自定義業務異常。
service層:接口的主邏輯,還有校驗參數。一般一個接口參數校驗應該越早越好,畢竟能早發現錯誤就早發現錯誤嘛,可是咱們這邊的規範是參數校驗在service層。
dao層:很少說了。
由於dubbo接口是不能直接被app調用的,因此咱們有個adaptor,算一個單獨的項目,他會把app的http請求,轉換成dubbo的入參,而後調咱們的dubbo接口。
說是說的很順暢,寫的時候,我是很疑惑。
export層,它針對的是app的一個功能,對外暴露的接口複用性太差。
facade層,說是接口的業務流程,由於接口的主邏輯在service層,我看到不少人的代碼,這一層就是調了一下service,致使這一層很薄,缺乏存在的意義。
service層,參數校驗,業務邏輯,調外部應用的接口,組裝對象,過重了,徹底不可複用。
dao層,我以前告誡公司的實習生,這裏能複用就複用,而後公司的其餘同事,卻告誡他們能不復用就不復用。dao層的方法過多。
實體類,除了有和表關聯的一個實體,入參和出參的實體只和app的功能相關,徹底不可複用。
有一天和同事聊到這個項目,他是負責review 代碼的一員,他說了句,"感受大家寫的代碼都是一次性代碼」,雖然我不知道他的理解跟我是否同樣,可是我也是深有同感。固然真正開發的時候,不是一些理論所能歸納全的。我總結一下本身作的項目,聊一聊本身的見解吧。
先談一下實體類
DO,我以前的公司把它定義爲什麼數據庫對應的實體,其實它應該是個domain entity。它包含了數據庫的全部字段,同時也包含了這個領域的其餘關聯對象,由於在一個領域內,可使用sql的關聯查詢,沒必要在爲了關聯查詢新建一個類。
DTO,數據傳輸對象,DO使咱們從數據庫獲得的領域對象,而DTO每每也包含了多個領域的信息,因此咱們須要轉成DTO。
VO,其實它也屬於DTO的一種。
Query,查詢入參的後綴,一樣屬於DTO。
而後談一下分層
action或者export:它負責入參和出參,對於普通的http應用它就是咱們一般用struts2實現的action、用springMVC實現的controller。對於企業內部,可能不是使用http協議,但它依然負責某個應用的入參和出參。
ao或者facade:它的確是個門面,負責調用本領域的接口,和跨領域的接口
manager或者service:本領域的業務
dao:數據層。
其中Service和Dao層操做的對象理論上只應該有DO和query。
facade和export層操做的對象,理論上只應該有DTO,VO和Query。咱們在facade層作對象的轉換,DO轉DTO,轉VO。固然對象轉換的操做最好交由具體的實體類操做。
由於service層和dao層是當前領域的業務,因此它們可能比較薄。業務最好保證必定的原子性,功能上保證鬆耦合,高複用。
facade層屬於應用層,應用層要保證業務邏輯的乾淨,通用的業務,能夠考慮模板。它的變化可能也比較快,固然若是service作的好的好的話,就是service的堆積了。
固然,好的架構師一點一點摸索,修改出來的,這裏只是本身的一些總結。