1

我已经阅读了双调度模式,它可以将服务接口传递给聚合方法:https ://lostechies.com/jimmybogard/2010/03/30/strengthening-your-domain-the-double-dispatch-pattern/ , http://blog.jonathanoliver.com/dddd-double-dispatch/

在我的域中,我有一个BitbucketIntegration聚合,它是远程 bitbucket 帐户的本地副本,其中 包含一些额外的域特定数据。现在,我必须从云同步存储库和团队等,以便能够在它们上进行业务操作。在我的第一个实现中,我使用服务访问 Bitbucket Cloud,然后设置聚合的存储库、团队、帐户。通过这种方式,我将DDDAnemic Domain Model混合在一起,因为一半的聚合状态是使用服务中的类似 setter 的方法设置的。使用Double Dispatch,我可以通过例如BitbucketService接口到方法参数。这样,聚合可以更多地保护它的不变量,因为某些数据只能通过连接到其余服务来验证(例如,如果聚合的accessToken,bitbucketAccountrepositories同步),这是服务的责任。还有一件事是accessToken我的聚合中有一个字段,这只是一个技术问题。

是否有任何推荐的模式将远程资源的副本保存在 ddd 聚合中?另外,如何避免技术方面的影响?还是第一种使用域服务的方法足够好?

现在代码看起来像:

class BitbucketIntegration extends Aggregate<UUID> {

    accountId: BitbucketId 
    repos: List<Repository>
    localData: ...
    // ... and more

    Single integrateWith(accessToken, queryService) {
        var id = queryService.getAccountAsync(accessToken);
        var repos = queryService.getReposAsync(accessToken);
        return Single.zip(id, repos, 
                (i, r) -> new BitbucketIntegratedEvent(accessToken, i, r))
            .onSubscribe(event -> apply(event))
    }

    Observable doSomeBusinessLocally(data) { ... return events; } 

    // this is triggered by a saga
    Single pollForChanges(queryService) {
        var dataFromRemote = queryService.synchronizeAsync(this.accessToken);
        ....
        return event;
    }
}

class CommandHandler {
    queryService: BitbucketService

    Completable handle(integrateCmd) {
        aggregate = repo.get(integrateCmd.id);
        return aggregate.integrateWith(integrateCmd.accessToken, queryService)
            .flatMap(event -> repo.store(event));
    }
}

作为旁注,我只查询Bitbucket。

编辑: Martin Fowler 写了关于访问外部系统的文章,包括定义反腐败层,它将远程资源表示转换为域类型。

4

1 回答 1

3

如果您将基础设施服务注入聚合(通过构造函数或方法调用),那么您将不再拥有域模型。这甚至包括在领域层中定义了接口的服务。它会影响可测试性并引入对基础架构的依赖。它也打破了单一责任原则,它迫使聚合知道它并不真正需要的东西。

解决这个问题的方法是先调用服务并将结果传递给聚合的方法(即在应用层)。

于 2018-01-06T17:16:44.650 回答