天天看点

NLayerAppV3--DDD之领域层

回顾: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的查询规约

NLayerAppV3--DDD之领域层
NLayerAppV3--DDD之领域层
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

实现了转账领域服务的逻辑。

NLayerAppV3--DDD之领域层
NLayerAppV3--DDD之领域层
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