我读过的有关DDD的一些文字表明应用层中的应用服务或命令(CQRS)与特定用例密切相关。
对于简单的用例,这种映射是有意义的,但在需要多次用户交互的更复杂的实例中,我试图了解如何映射API的courser粒度级别,而不将应用程序逻辑推入UI。 / p>
实施例: - 想象一下应用服务:
ImportProductData(date_source)
我通常的做法: 展开API以包含:
DoesIncludeExistingProducts(data_source)
如果返回true,则提示用户是否要继续,然后致电。
ImportProductData(date_source, overwrite=True)
我的问题是,这是否正在将大部分应用程序逻辑转移到UI层? (即UI现在控制是否可以覆盖产品,以及在导入产品数据之前是否应检查现有产品等)
如果是,我无法想象应用程序和域层将如何处理这个问题?除了:
通话:
ImportProductData(date_source)
如果失败,请检查失败原因,如果产品已经存在,请提示用户并再次致电:
ImportProductData(date_source, overwrite=True)
这感觉就像上面做同样的事情。
这可能看起来有点迂腐,但我正在努力使表达层(MVC)尽可能轻薄。
关于更优雅的解决方案的想法?
答案 0 :(得分:1)
在用户发出真正的命令以执行可能会改变的事情之前,您不应该访问ApplicationServices。
什么阻止您在MVC演示模式中使用控制器使用的ViewServices层来执行您要求的操作?
答案 1 :(得分:1)
首先在这里查看Jimmy Bogards的启发帖https://jimmybogard.com/domain-command-patterns-validation/。他没有回答你的问题,但是以一种让你更容易下定决心的方式攻击它。
在那篇文章中,他简要地谈到了一个我认为需要更多关注的观点。如果“用户经常尝试执行我的域验证不允许的操作”,他建议不要将异常用作通信机制。使用这个标准,我更愿意分解那些预期有时会失败进入验证调用然后执行调用的用例。
在您的情况下,似乎适合使用验证查询(而不是命令),例如IsProductSetValidForImport。在上面的Jimmy的文章中,他努力决定返回的错误集应该有多丰富,但是查询的返回集应该是丰富的,所以我们没有问题。您可以返回一个真实的,完全形成的视图模型,以显示给用户,而不是尝试将足够的数据填充到错误字符串中以绘制屏幕。我假设如果10个产品中有3个导致导入失败,您可能希望允许用户强制更新某些产品而不是其他产品。这给了你这个机会。
如果此验证查询未返回任何冲突,请向用户提供“您确定”消息,然后调用API以执行导入命令。如果在您调用验证查询的时间和发出更新命令的时间之间发生了一些重要的状态改变,那么抛出异常并处理后果是合适的。