回顾:NLayerAppV3是一个使用.net 2.1实现的经典DDD的分层架构的项目。
NLayerAppV3是在NLayerAppV2的基础上,使用.net core2.1进行重新构建的;它包含了开发人员和架构师都可以重用的DDD层。
Github地址:https://github.com/cesarcastrocuba/nlayerappv3
上一篇,介绍了NLayerAppV3项目Infrastructure(基础设施层)的Cross-Cutting部分,文章地址:https://www.cnblogs.com/net-yuan/p/NLayerAppV3-Infrastructure_CrossCutting.html
NLayerAppV3的基础结构层一共分为两个部分。处理数据相关的基础组件Data和Cross-Cutting的基础组件。
处理数据相关的基础组件Data主要包含UOW和仓储的实现;
Cross-Cutting的基础组件目前主要包含数据适配器、国际化、验证;
这篇本来应该介绍Infrastructure(基础设施层)的Data部分。
可是仓储的具体实现是放在基础结构层的,而仓储的接口则是放在领域模型层的。
所以,我们就先介绍领域层Domain。
NLayerAppV3项目的Domain(领域层)分为两个部分:Seedwork和BoundedContext
Seedwork部分定义了实体的契约、实体的基类、值对象的基类、仓储的契约、UOW的契约、规约等。
BoundedContext部分定义了聚合相关,聚合、值对象、规约的具体实现、仓储的契约、领域服务等。
以下描述引用自何老大的博文:
聚合包装一组高度相关的对象,作为一个数据修改的单元。
聚合最外层的对象称为聚合根,它是一个实体。聚合根划分出一个清晰的边界,聚合根外部的对象,不能直接访问聚合根内部对象,如果需要访问内部对象,必须首先访问聚合根,再导航到聚合的内部对象。
聚合代表很强的包含关系,聚合内部的对象脱离了聚合,应该是毫无意义的,或不是你真正关注的,它是聚合的一个组成部分,这与UML中的组成聚合概念相近。
有关聚合的相关知识可以查看何老大的博文 https://www.cnblogs.com/xiadao521/p/4141904.html
以BankAccount聚合来看,BankAccount是聚合根,包含卡号BankAccountNumber这样的值对象,BankAccountNumber由国家或者地区银行编号、检查位等构成;Balance金额、Locked是否锁定、Customer用户实体、BankAccountActivity账户活动的集合等等、还包含锁定、解锁、存款等行为。这是一个充血的模型。
BankAccountFactory是创建聚合BankAccount的工厂,它负责创建BankAccount。
BankAccountSpecifications封装了BankAccount的查询规约
public static class BankAccountSpecifications
{
/// <summary>
/// Specification for bank accounts with number like to <paramref name="ibanNumber"/>
/// </summary>
/// <param name="ibanNumber">The bank account number</param>
/// <returns>Associated specification</returns>
public static ISpecification<BankAccount> BankAccountIbanNumber(string ibanNumber)
{
Specification<BankAccount> specification = new TrueSpecification<BankAccount>();
if (!String.IsNullOrWhiteSpace(ibanNumber))
{
specification &= new DirectSpecification<BankAccount>((b) => b.Iban
.ToLower()
.Contains(ibanNumber.ToLower()));
}
return specification;
}
}
View Code
IBankAccountRepository提供了BankAccount的仓储契约
IBankTransferService提供了转账的领域服务契约,有一个转账方法
void PerformTransfer(decimal amount, BankAccount originAccount, BankAccount destinationAccount);
BankTransferService实现了IBankTransferService
实现了转账领域服务的逻辑。
public void PerformTransfer(decimal amount, BankAccount originAccount, BankAccount destinationAccount)
{
if (originAccount != null && destinationAccount != null)
{
var messages = LocalizationFactory.CreateLocalResources();
if (originAccount.BankAccountNumber == destinationAccount.BankAccountNumber) // if transfer in same bank account
throw new InvalidOperationException(messages.GetStringResource(LocalizationKeys.Domain.exception_CannotTransferMoneyWhenFromIsTheSameAsTo));
// Check if customer has required credit and if the BankAccount is not locked
if (originAccount.CanBeWithdrawed(amount))
{
//Domain Logic
//Process: Perform transfer operations to in-memory Domain-Model objects
// 1.- Charge money to origin acc
// 2.- Credit money to destination acc
//Charge money
originAccount.WithdrawMoney(amount, string.Format(messages.GetStringResource(LocalizationKeys.Domain.messages_TransactionFromMessage), destinationAccount.Id));
//Credit money
destinationAccount.DepositMoney(amount, string.Format(messages.GetStringResource(LocalizationKeys.Domain.messages_TransactionToMessage), originAccount.Id));
}
else
throw new InvalidOperationException(messages.GetStringResource(LocalizationKeys.Domain.exception_BankAccountCannotWithdraw));
}
}
View Code
参考: dax.net https://www.cnblogs.com/daxnet/archive/2011/06/07/2074451.html
何镇汐 https://www.cnblogs.com/xiadao521/p/4141904.html