背景
一個類型可以充當多個角色,這個角色可以是顯式的(實現了某個接口或基類),也可以是隱式的(承擔的具體職責和上下文決定),本文就討論四個角色:數據模型、領域模型、視圖模型和命令模型。
四個角色
- 數據模型:面向持久化,數據的載體。
- 領域模型:面向業務,行為的載體。
- 視圖模型:面向UI(向外),數據的載體。
- 命令模型:面向UI(向內),數據的載體。
這是四種角色,可以由一至四個類型來承擔,具體選擇幾個類型需要考慮項目的上下文,但不同的選擇對編程的要求是不同的,下面舉幾個例子。
數據模型和領域模型采用統一個類型,采用EntityFramework進行持久化。
這種設計毫無疑問對這個類型是有侵入性的,即使采用了POCO,如果需要延時加載,也只能做到編譯時的POCO,運行時還是會生成代理類型,某些成員需要生命為virtual,你還需要記得默認構造方法和屬性的setter都會被EntityFramework在重建對象時候調用。一個類型承擔了兩個角色,就要完成兩份職責(持久化和封裝業務邏輯),這或許違背了單一職責原則,不過某些情況下這是最好的選擇了。
四個角色采用一個類型
這種設計適合業務邏輯不是很復雜的場景,系統中只有CRUD,以四色原型為例,PPT和Des適合采用這種模式。因為這個類型要承擔四個角色,所以沒辦法采用顯式的封裝技術,所有成員都是Public { get; set; },考慮到很多動態語言其實是沒法封裝的(是按照約定),或許C#開發者可以接受這種設計,比如:雖然集合被公開了,但是我們還是可以采用封裝集合模式,外部調用的時候要根據約定采用封裝過的接口,TDD有利於強制這種約定,示例代碼:
1 public class Order 2 { 3 public List<OrderItem> Items { get; set; } 4 5 public void AddItem(OrderItem item) {} 6 }
為視圖模型引入單獨的類型
你采用了WCF技術,你的UI期望的數據和領域模型非常不匹配(也是一種阻抗不匹配),這時你就會引入視圖模型。如何構造視圖模型呢?一般來說有兩種思路:一、用AutoMapper之類的工具從領域模型映射;二、采用輕量級的框架(PetaPoco)直接從表、視圖和存儲過程返回。
備注
今天只是大概聊了聊這樣一個想法,下一步會寫一些Demo驗證幾種不同的組合。
