淺談工程目錄結構——包命名和分層職責問題

首先,基於約定俗成的命名習慣,我們常見的包名大致可羅列如下:

數據對象類:bean/entity/pojo/model/dataobject/domain/enum/constant;

持久層倉庫資源類:dao/repository/mapper;

業務層:service/action/manager/biz

控制器層:controller/web/ctrl/facade

工具設施層:utils/tools/

切面橫切邏輯:aspect/aop

攔截器:interceptor/filter

全局配置:config/configration

自定義異常:exception

轉換器:converter

表單對象:form      

......
以上單詞及相應的複數形式,我們較爲常見,很多基於類的職能進行命名,也有根據採用不同框架歷史沿革進行命名,如mabatis用mapper,SSH框架的業務層用action,springJPA的持久層用repository等;命名雖不強制,但保持這種事實上的約定,交流項目、維護管理會很方便。

儘管大家在項目着手時都會有模有樣的攢出這樣一個架子來,但包括我在內的很多新手對於各層級、各包的職責可能依然會混淆。在經過思考和比對一些我所見過的項目,本文做一些個人理解闡述,如有不當,歡迎指正。

首先,我提倡包結構不要嵌套過深,在src/main/java/com.groupName.projectName目錄下,按照上述分層分好包後,每個包最好不要超過兩層子包的嵌套。比如service下,可能有接口和Impl實現包,實現包下又可能又分出一個xxxmock包用於打樁測試,這就可以了,不要再深入嵌套了。

然後說一說各層的職責。

控制層:通常作爲業務驅動的事件入口,一般與客戶端(包括桌面、web等GUI、命令行等)打交道,作爲interface(界面/接口),是客戶端與服務層之間建立的穩定的抽象屏障;其核心職責就是負責接收請求,並校驗參數,數據綁定、適配轉換,調用服務層組件後,處理結果並響應。很多人伊始,不自覺地就會把業務邏輯寫到控制層,這不能說不對或不行,而是違背了分層的初衷,混淆了層次。提起適配,也有很多人喜歡將vo、bo、po、dto等對象分清楚,這本是爲解耦而爲,但也有朋友混合在各層傳輸它們。比如把control層用的Vo傳給Biz層,我認爲在biz層去convert,這從源碼依賴的角度來說,就違背了向下依賴的原則。依我之見,應該“誰主張,誰舉證”,即誰是調用方,誰負責convert工作。也就是說應該在control層拿到vo接收的參數後,在調用service層方法時,提前轉換成service層需要的bo;service層聲明接口時,就強硬的對外聲明“我需要xxxBo”;同理,Dao接口就對外聲明:“我需要xxxPo”對象;提取數據時也一樣,service層調用Dao層返回xxxPo時,自己轉換成業務對象。反之,如果被調用方負責轉換數據,那就需要知曉上層數據結構,違背了“上層對於下層而言不可見“的原則,況且這也不是它分內的事,服務組件就要專注業務邏輯。

業務層:我這樣理解業務層,它通過組織例程單元及各種資源,進行腳本化形成的應用服務上下文。本質上,是分佈在不同命名空間裏的資源在此按一定時序排列組合形成的上下文場景。然後對外暴露服務接口提供內核服務。雖然開發過程中會考慮到與控制層的接洽,但考慮到模塊複用,理論上該層可不受限於上層約束,獨立的制定接口。整個過程就像一個boss抓壯丁去組織各個worker幹活一樣,一個派發函數,或一個上下文場景類,乃至一整套服務模塊,都在扮演一個調度員的角色。

持久層:作爲數據訪問對象,與持久化機構進行讀寫交互,不關心業務邏輯,只執行上級命令如實提供數據源,數據怎麼用不是它該關心的。當然,持久層是個廣義的含義,我認爲能提供數據倉儲作用的對象都可以置入該層,比如緩存組件。

模型層:嚴格的說,它不算是某一層,層是一個基於業務流所處不同階段而劃分的概念;模型中,無論是視圖對象、普通值對象、或帶有oid的實體數據對象,都可以說是被操縱的數據。因爲編程無外乎就是對象調方法或方法操縱對象,用自然語言表述就是主語-動詞-賓語的組合過程。當然你可以說方法也可以作爲數據傳入方法或返回,的確,往深了說,一切都是對象/數據,方法/函數也是對象;一切又都是函數,因爲對象的定義也需要通過構造、選擇、賦值函數來進行定義;一切對象在一個命名空間/上下文下,又可作爲屬性...所以,過程和數據抽象在本質上是統一的。我們這裏考慮一般意義上的編程範式,將數據和過程分離,那麼模型這一層的確是貫穿整個應用各層始終的。不難看出,所謂的vo\bo\po其實就是模型在業務流轉過程中不同階段的特稱。

外圍設施:比如util包,我個人習慣把無關核心業務邏輯的其他模塊稱爲外圍設施。用來提供基礎、輔助職能,如字符串、日期處理、rpc通信、編解碼等工具類,通用小部件等。就像一個國家的基建事業一樣。

環境:比如config包,一般用於工程整體環境、框架配置等。

其他按具體職能命名的包就不用贅述了。

總之,既然按照MVC去分層架構,就是爲了降低耦合、維護起來清晰、容易複用,因此一定要認真審視各層的角色和職責,以及所開發組件的業務邊界,不要讓工程結構徒有其形,內部依賴混亂一塌糊塗。那就金玉其外敗絮其中了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章