聚合可以使用聚合查找服务,还是业务逻辑应该在域服务中?

时间:2019-08-25 13:32:38

标签: c# domain-driven-design cqrs event-sourcing

我正在使用带有事件源的CQRS开发DDD软件。现在,我试图找出应该将业务逻辑放在哪里。

我有一个条件汇总根,它引用了triggerId(触发汇总根)。我还有一个conditionGroup聚合根,其中包含conditionId的列表。而且我有一个看门狗聚合根,其中包含一个conditionGroupId。

当调用触发器聚合Create方法时,域将发出triggerReceived事件。 triggerReceived事件具有triggerId和一个value属性,应该由与该条件聚集中的triggerId链接的条件检查该条件。

我在域一侧有一个订阅者,它在监听此事件。我的计划是检索订户中的所有监视程序,并调用方法watchdog.ShouldBark(triggerId,value)。然后,看门狗需要查找ConditionGroup聚合(它具有ConditionGroupId作为属性)并调用ConditionGroup.DoesGroupMatch(triggerId,value)。 ConditionGroup必须查找所有Condition聚合(它具有conditionId列表),并调用Condition.DoesConditionMatch(triggerId,value)方法。

因此,每个聚合必须查找其他聚合以访问进行某些检查(不进行任何更新)的业务逻辑方法。

还是在域中提供一些watchdogService更好,而watchdog服务执行所有汇总查找并具有业务逻辑?

所以我的问题是:聚合可以通过使用接口(IAggregateStore)进行业务逻辑检查来查找其他聚合(无更新,因为每个事件仅应更新一个聚合)?

1 个答案:

答案 0 :(得分:1)

您的描述还很不完整,因此此答案也可能不完整。 根据您的描述-

  

我在域端有一个订阅者,它在监听此事件。我的计划是检索订户中的所有看门狗,并调用方法watchdog.ShouldBark(triggerId,value)。

在您的域设计中,我会闻到非常不好的气味。 ShouldBark 方法的目的是什么。它必须更改您的WatchDog域的状态。如果真是这样,您的方向就会错误。

让我们首先获取您的业务领域。 触发 条件 条件组 WatchDog

  

我有一个条件聚合根,它引用了triggerId(触发聚合根)。

因此,触发器聚合中的代码应如下所示(您可能发现我的某些代码是伪代码)-

public class Trigger : AggregateRoot
{
    ...
    public void CreateTrigger(int value)
    {
        //You can also pass new guid for trigger from your service
        Guid triggerId = Guid.NewGuid();
        var @event = new TriggerReceived(triggerId, value);
        PublishEvent(@event);
    }
}

//this is your event
public class TriggerReceived
{
    public readonly int Value;
    public readonly Guid TriggerId;
    public TriggerReceived(Guid triggerId, int value)
    {
        Value = value;
        TriggerId = triggerId;
    }
}

现在,朝正确的方向前进。无需检索所有的WatchDog,请订阅您的 Condition 服务到该事件。

public class ConditionService
{
    public void When(TriggerReceived @event)
    {
        //re-hydrate your condition aggregate root from event store
        var condition = getConditionByTriggerId(@event.TriggerId);
        //if you want to retrieve condition based on Value you can do that here
        //var condition = getConditionByValue(@event.Value);
        if(condition is not null)
            condition.MatchTrigger();
    }
}

然后在您的条件汇总中-

public class Condition : AggregateRoot
{
    ...
    public void MatchTrigger()
    {
        //your business logic here
        ...
        //we know trigger value matched one condition, so raise the next event
        publish(new TriggerConditionMatched(this));
    }
}

//this is your TriggerConditionMatched event
public class TriggerConditionMatched
{
    public readonly Condition Condition;
    public TriggerConditionMatched(Condition condition)
    {
        Condition = condition;
    }
}

基于此-

  

我还有一个conditionGroup聚合根,其中包含conditionId列表。

我们还可以声明,每个条件都应具有一个名为 ConditionGroupId 的属性。订阅您的 ConditionGroup 服务以收听上述活动-

public class ConditionGroupService
{
    public void When(TriggerConditionMatched @event)
    {
        //re-hydrate your condition group aggregate root from event store
        var conditionGroup = getConditionGroup(@event.Condition.GroupId);

        if(conditionGroup is not null)
            conditionGroup.MatchTriggerToConditionGroup();
    }
}


public class ConditionGroup : AggregateRoot
{
    ...
    public void MatchTriggerToConditionGroup()
    {
        ...
        //do some check here, your business logic

        //raise the next event
        publish(new TriggerConditionGroupMatched(this));
    }
}

//this is your TriggerConditionGroupMatched event
public class TriggerConditionGroupMatched
{
    public readonly ConditionGroup ConditionGroup;
    public TriggerConditionGroupMatched(ConditionGroup conditionGroup)
    {
        ConditionGroup = conditionGroup;
    }
}

最后,基于此-

  

而且我有一个看门狗聚合根,其中包含一个conditionGroupId。

您应该在 ConditionGroup 域中拥有一个watchDogId属性。因此,订阅您的 WatchDog 服务以收听 TriggerConditionGroupMatched 事件-

public class WatchDogService
{
    public void When(TriggerConditionGroupMatched @event)
    {
        //re-hydrate your Watch Dog aggregate root from event store
        var watchDog = getWatchDog(@event.ConditionGroup.WatchDogId);

        if(watchDog is not null)
            watchDog.Bark();
    }
}

public class WatchDog : AggregateRoot
{
    ...
    public void Bark()
    {
        ...
        this.ShouldBark = true;

        //you should raise your next event
        publish(nextEvent);
    }
}

您可能已经发现这是一个由事件和订阅者组成的网络,但是请记住,事件源系统最终应始终保持一致。这样,您就可以记录发生在触发器条件 ConditionGroup WatchDog 上的所有事件。 >