一、貧血模型
所謂貧血模型,是指Model 中,僅包含狀態(屬性),不包含行為(方法),采用這種設計時,需要分離出DB層,專門用於數據庫操作。
二、充血模型
Model 中既包括狀態,又包括行為,是最符合面向對象的設計方式。
以下為舉例說明:
對於員工Employee來說,每個員工的屬性有Id,Name,Sex,BirthDay,Parent(上級),行為有查找,保存,刪除,職位調整(更換上級) 等
采用貧血模型實現
Model:

public class Employee { public string Id { get; set; } public string Name { get; set; } public string Sex { get; set; } public DateTime? BirthDay { get; set; } /// <summary> /// 直屬上級的Id /// </summary> public string ParentId { get; set; } }
DB 層

//實現方法略 public class EmpDAO { public static bool AddEmployee(Employee emp); public static bool UpdateEmployee(Employee emp); public static bool DeleteEmployee(Employee emp); public static Employee GetEmployeeById(string Id); }
BLL 層

public class EmpBLL { public void Test() { Employee emp1 = new Employee() { Id = System.Guid.NewGuid().ToString(), Name = "張三", Sex = "男" }; Employee emp2 = new Employee() { Id = System.Guid.NewGuid().ToString(), Name = "李四", Sex = "男", ParentId = emp1.Id }; //插入員工 EmpDAO.AddEmployee(emp1); EmpDAO.AddEmployee(emp2); //取員工的上級 var emp2Parent = EmpDAO.GetEmployeeById(emp2.ParentId); var emp2Parent_Parent = EmpDAO.GetEmployeeById(emp2Parent.ParentId); //刪除員工 EmpDAO.DeleteEmployee(emp1); EmpDAO.DeleteEmployee(emp2); } }
若采用充血模型設計,則應只分兩層 ,Model 層(包含狀態和行為)和Service(BLL) 層
Model 層

public class Employee { public string Id { get; set; } public string Name { get; set; } public string Sex { get; set; } public DateTime? BirthDay { get; set; } /// <summary> /// 直屬上級的Id /// </summary> public string ParentId { get; set; } private Employee _parent; public static Employee query(string id) { Employee emp = new Employee(); //實現略,僅需填充emp的熟悉即可 return emp; } /// <summary> /// 保存對象,實現略 /// </summary> /// <returns></returns> public bool Save() { return true; } /// <summary> /// 刪除對象,實現略 /// </summary> /// <returns></returns> public bool Drop() { return true; } /// <summary> /// 上級領導,此處直接獲得了Employee對象 /// </summary> public Employee Parent { get { if (_parent != null) { return _parent; } else { _parent = query(this.ParentId); return _parent; } } set { _parent = value; this.ParentId = _parent.Id; Save(); } } }
Service 層

public class EmpService { public void Test() { Employee emp1 = new Employee() { Id = System.Guid.NewGuid().ToString(), Name = "張三", Sex = "男" }; Employee emp2 = new Employee() { Id = System.Guid.NewGuid().ToString(), Name = "李四", Sex = "男", ParentId = emp1.Id }; //插入員工 emp1.Save(); emp2.Save(); //取員工的上級 var emp2Parent = emp2.Parent; var emp2Parent_Parent = emp2Parent.Parent; //刪除員工 emp2.Drop(); emp1.Drop(); } }
總結:
從兩者Service層和BLL 層的代碼區分來看,兩者都是實現了業務功能和延遲加載。
貧血模型優點是系統的層次結構清楚,各層之間單向依賴。缺點是不夠面向對象。
充血模型優點是面向對象,Business Logic符合單一職責,不像在貧血模型里面那樣包含所有的業務邏輯太過沉重。缺點是比較復雜,對技術要求更高。
對於web開發,個人推薦用貧血模型。其實無論是采用哪種模型,都是可以的,只不過作為我們自己,要真正去理解為什么要這么做,以及怎樣去解決問題,而不是學到一知半解,把兩種方式混用,分出DAL 層來,卻又采用充血模型去操作,然后又去遵循貧血模型的規范,把代碼寫的亂七八糟,層不是層(吐槽一下,在這樣的項目里,讓我很難受)。
好的代碼,應該是簡單的,應該是美的,應該是能解決問題而不是制造問題的,不要為了面向對象而面向對象。
以上都是我的個人理解,有不對的地方,歡迎大家指正。
ps:最近在做項目,發現有人在貧血模型中使用Parent類似的這種類,但是又不能解決延時加載的問題,或者是每次用的時候都要再加載,沒有添加Parent的意義,反而導致這些對象不能及時回收,心有所感,所以在這里總結一下,與大家分享。