前邊我們構建了個數據訪問層,功能雖然簡單,但是基本夠用了。傳送門:項目架構開發:數據訪問層
這次我們構建業務邏輯層
業務邏輯是一個項目、產品的核心,也是現實世界某種工作流程在代碼層面的體現。
所以,業務邏輯的合理組織構造,或更真實地反映現實業務操作,對項目的成功與否非常重要
現在業界對業務邏輯層的開發,一般會參考Martin Fowler大師提出來的針對業務層開發的四種模式
分別是面向過程的事務腳本、表模塊模式,面向對象的活動記錄與領域開發模式
我們要做的就是領域驅動開發模式,注意標題中的“失血模式”,我們的業務領域模型不是貧血與充血,而是失血;
這意味着領域模型只有get;set;,模型的所有行為都在領域模型之外,我們的領域邏輯在IRepository組件中、應用邏輯在Application組件中
1、領域模型

LoginUser.cs
1 using System; 2 3 namespace Business.ReverseDDD.Model 4 { 5 public class LoginUser 6 { 7 public Guid? Id { get; set; } 8 public string LoginName { get; set; } 9 public string Password { get; set; } 10 public int? IsEnabled { get; set; } 11 public DateTime? CreateTime { get; set; } 12 } 13 }
ILoginUserRepository.cs
1 using Business.ReverseDDD.Model; 2 using Infrastructure.Interface; 3 4 namespace Business.ReverseDDD.IRepository 5 { 6 public interface ILoginUserRepository : IRepository<LoginUser> 7 { 8 } 9 }
LoginUser實體實際上就是與數據表對於的PO,只有屬性,沒有任何邏輯,嚴格來說都不算是一個模型
IRepository是定義模型具有哪些方法,這里直接繼承前邊數據訪問層的基礎接口,這里再貼一次
IRepository.cs
1 public interface IRepository<T> where T : class 2 { 3 void Add(T entity); 4 void AddBatch(IEnumerable<T> entitys); 5 void Update(T entity); 6 void Delete(T entity); 7 void Delete(string Id); 8 void Delete(int Id); 9 void Delete(Guid Id); 10 T Get(string Id); 11 T Get(Guid Id); 12 T Get(int Id); 13 T Get(T entity); 14 T Get(Expression<Func<T, bool>> func); 15 IEnumerable<T> GetAll(); 16 IEnumerable<T> GetList(Expression<Func<T, bool>> where = null, Expression<Func<T, bool>> order = null); 17 Tuple<int, IEnumerable<T>> GetPage(Page page, Expression<Func<T, bool>> where = null, Expression<Func<T, bool>> order = null); 18 long Count(Expression<Func<T, bool>> where = null); 19 }
可以看到,模型只有一些簡單的CURD操作,而且訪問僅限於自己領域內,如果要自定義功能,要在ILoginUserRepository中擴充
我們再來看看LoginUser模型的一個具體實現

LoginUserRepository.cs
1 public class LoginUserRepository : BaseRepository<LoginUser>, ILoginUserRepository 2 { 3 public LoginUserRepository(IUnitOfWork<LoginUser> unitOfWork) 4 : base(unitOfWork) 5 { 6 7 } 8 }
這里也是繼承前邊數據訪問層的BaseRepository.cs類,這個類有點長,就不貼了,可以到前邊看看詳細的
好了,現在我們的領域邏輯做好了,模型的CURD都已經委托給了基礎設施層來做。現在可以開始對構建應用邏輯了
2、構建應用邏輯

LoginUserApplication.cs
1 using Business.DTO.Request; 2 using Business.ReverseDDD.IRepository; 3 using Business.ReverseDDD.Model; 4 using Business.ReverseDDD.Repository; 5 using Infrastructure.Data.UnitOfWork; 6 using Infrastructure.Interface; 7 8 namespace Business.ReverseDDD.Application 9 { 10 public class LoginUserApplication 11 { 12 private IUnitOfWork<LoginUser> unitOfWork; 13 private ILoginUserRepository repository; 14 15 public LoginUserApplication() 16 { 17 this.unitOfWork = new UnitOfWork<LoginUser>(); 18 this.repository = new LoginUserRepository(this.unitOfWork); 19 } 20 21 public bool Login(LoginRequest entity) 22 { 23 var user = this.repository.Get(w => w.LoginName == entity.LoginName); 24 25 if (user == null) return false; 26 if (user.Password != entity.Password) return false; 27 28 return true; 29 } 30 } 31 }
這里可以用IOC的方式解耦UnitOfWork
應用邏輯層Evans的定義是這一層保持簡單,並不需要了解業務規則,將業務規則直接傳給下一層領域模型完成就OK了
但是我們是失血模型,模型內沒有領域邏輯的實現,所以這一層必須實現所有業務邏輯
還有請注意LoginRequest這個參數類,這個類是DTO對象,用於展示層與業務邏輯層傳輸數據用的,目的當然是為了解耦了
3、DTO

LoginUser.cs
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace Business.DTO.Request 7 { 8 public class LoginRequest 9 { 10 public string LoginName { get; set; } 11 public string Password { get; set; } 12 } 13 }
非常簡單,只是一些傳輸參數的實體類,我們再新建一個測試項目看看實際運行效果
4、UnitTest

LoginUserApplicationTest.cs
1 public class LoginUserApplicationTest 2 { 3 public LoginUserApplicationTest() 4 { } 5 6 [TestMethod] 7 public void Login() 8 { 9 var loginUserApplication = new LoginUserApplication(); 10 var flag = loginUserApplication.Login(new LoginRequest() 11 { 12 LoginName = "lanxiaoke-333", 13 Password = "mima1987" 14 }); 15 16 Assert.AreEqual(true, flag); 17 } 18 }
表數據

運行結果

好了,貌似沒什么問題;看一下完整方案

最后總結:
我最近正在學習充血模型的DDD,也知道這篇所謂的“領域驅動”其實跟真正的領域開發有很大的差距,甚至不是真正的OO,只是事務腳本的變種而已
從網上搜了一些DDD的demo, 貌似就流行這么搞;這讓我很詫異。但是這種模式也是有很大好處的:足夠簡單、適合分層並行開發
在項目初期的速度大大高於充血模型的速度;業務充血模型需要具備的業務領域能力太高,單單建模就花很多時間,
在現在這種互聯網公司,多數老板不讓你這么搞,都是草草了事。反正我完成了的任務,管他后邊洪水滔天,所以搞的大家都很浮躁
