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

问题描述 投票:0回答:1

我正在通过使用带有事件源的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)进行业务逻辑检查来查找其他聚合(无更新,因为每个事件仅应更新一个聚合)?

c# domain-driven-design cqrs event-sourcing
1个回答
0
投票

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

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

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

让我们首先获取您的业务领域。 TriggerConditionConditionGroupWatchDog

我有一个条件聚合根,它引用了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);
    }
}

您可能已经发现这是一个由事件和订阅者组成的网络,但是请记住,事件源系统最终应始终保持一致。这样,您可以记录TriggerConditionConditionGroupWatchDog发生的所有事情的日志。

© www.soinside.com 2019 - 2024. All rights reserved.