美文网首页
DDD战术落地—聚合的编排一定要在应用层吗?(领域服务与领域对象

DDD战术落地—聚合的编排一定要在应用层吗?(领域服务与领域对象

作者: 小胖学编程 | 来源:发表于2022-07-24 11:35 被阅读0次

    先说结论:我个人认为不是的。

    悖论

    网上很多文章给出的结论:

    1. 推荐聚合划分越细越好;
    2. 聚合之间的编排应该放在应用层完成;

    但是这就出现了一个悖论,即一些核心的领域逻辑分在了两个聚合中,但是却只能在应用层去组合。造成了领域能力的外泄。

    举例

    举个“登录操作”例子:

    登录时,有“租户”和“用户名/密码”。用户登录时,首先判断是否在某个租户下,然后在判断该租户下用户名/密码是否相同。

    因为可以增删改租户信息,也可以增删改用户信息,所以租户和用户应该划分为两个聚合。

    领域建模图.png

    那么登录这一个行为:具体到代码就会变成了:

    boolean authentic=false
    //获取租户
    Tenant tenant= TenantRepo.tenantOfId(aTenantId);
    if(tenant!=null && tenant.isActive()){
        User user=UserRepo.userWithUserName(aTenantId,aUserName);
        if(user!=null){
            authentic=user.isAuthentic(aPassword);
        }
    }
    

    但是仔细想下,这个行为应该属于“认证授权”的行为,需要放在应用层进行编排处理吗?它会使得调用者的逻辑非常复杂。强加在客户端上的职责应该在我们的领域模型中予以解决。只与领域相关的信息决不能泄露到客户端。即使客户端是一个应用服务,它也不应该负责身份与访问权限的管理。

    客户端(应用层)需要处理的唯一业务职责:调用单个业务操作,而由改业务操作去处理所有的业务细节。

    解决方案:提供领域服务

    提供一个领域服务,来聚合多个领域对象。

    UserDescriptor userDescriptor=authenticationDomainService.authenticate(aTenantId,aUserName,aPassword);
    

    客户端只需要获取一个无状态的AuthenticationDomainService,然后调用authenticate,这种方式将所有的认证细节放在领域服务,而非应用服务。在需要的情况下,领域服务可使用任何领域对象完成操作,包括对密码的加密。

    客户端无需知道任何的细节。

    通用语言也得到了满足,因为我们将所有的领域术语都放在了身份管理这个领域,而非一部分放在领域模型,另一部分放在客户端(应用层)。

    领域服务方法返回了一个UserDescriptor值对象,这是一个很小的对象,并且是安全的,与User相比,它值包含了3个关键属性。

    public class UserDescriptor{
      private String emailAddress;
      private long tenantId;
      private String userName;
    }
    

    进阶:何时应该使用领域服务

    领域服务到底是什么?当领域中某个操作或者转换过程不是实体或者值对象的职责时,此时便应该将该操作放在一个单独的接口,即领域服务。

    请保证领域服务和通用语言是一致的,并且保证它是无状态的;

    通常领域模型主要关注特定某个领域的业务,同样,领域服务也具有相似特点。由于领域服务有可能在单个原子操作中处理多个领域对象,这将增加领域服务的复杂性。

    那么何时一个操作不属于实体或值对象?即何时可使用领域服务:

    • 执行一个显著的业务操作过程;
    • 对领域对象进行转换;
    • 以多个领域对象作为输入进行计算,产生一个值对象结果;

    当一个方法不便放在实体或者值对象,使用领域服务便是最佳的解决方案。

    领域服务与应用服务的区别

    • 应用服务并不处理业务逻辑;
    • 领域服务恰恰是处理业务逻辑;

    缺点:确定需要领域服务

    过度使用领域服务将导致贫血领域模型,即所有的业务逻辑都位于领域服务中,而非实体和值对象。

    文章参考

    DDD领域驱动设计实战(六)-领域服务

    相关文章

      网友评论

          本文标题:DDD战术落地—聚合的编排一定要在应用层吗?(领域服务与领域对象

          本文链接:https://www.haomeiwen.com/subject/ifmiirtx.html