項目架構開發:業務邏輯層之領域驅動失血模型


前邊我們構建了個數據訪問層,功能雖然簡單,但是基本夠用了。傳送門:項目架構開發:數據訪問層

 

這次我們構建業務邏輯層

業務邏輯是一個項目、產品的核心,也是現實世界某種工作流程在代碼層面的體現。

所以,業務邏輯的合理組織構造,或更真實地反映現實業務操作,對項目的成功與否非常重要

現在業界對業務邏輯層的開發,一般會參考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, 貌似就流行這么搞;這讓我很詫異。但是這種模式也是有很大好處的:足夠簡單、適合分層並行開發

在項目初期的速度大大高於充血模型的速度;業務充血模型需要具備的業務領域能力太高,單單建模就花很多時間,

在現在這種互聯網公司,多數老板不讓你這么搞,都是草草了事。反正我完成了的任務,管他后邊洪水滔天,所以搞的大家都很浮躁

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM