域驱动设计 – DDD:在控制器内部使用Value Objects?

前端之家收集整理的这篇文章主要介绍了域驱动设计 – DDD:在控制器内部使用Value Objects?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
当您从控制器中的UI接收到字符串格式的参数时,是否直接将字符串传递给应用程序服务(或命令)?

或者,您是否从控制器中的字符串创建值对象?

new Command(new SomeId("id"),Weight.create("80 kg"),new Date())

要么

new Command("id","80 kg",new Date())
new Command("id","80","kg",new Date())

也许这并不重要,但是让我烦恼.

问题是,我们应该将值对象从域耦合到(内部)控制器吗?

想象一下,您的应用程序层和表示层之间没有网络(如Android活动或swing),您是否会在UI中推荐使用值对象?

另一件事,你把值对象序列化到/从字符串这样排序

Weight weight = Weight.create("80 kg"); 
weight.getValue().equals(80.0);
weight.getUnit().equals(Unit.KILOGRAMS);
weight.toString().equals("80 kg");

在将字符串传递到命令的情况下,我宁愿通过“80公斤”而不是“80”和“kg”.

对不起,如果问题不相关或有趣.

谢谢.

UPDATE

当我搜索关于完全不同的主题的信息时,我遇到了这个帖子:Value Objects in CQRS – where to use

他们似乎更喜欢原语或DTO,并将VOs保留在域内.

我也看过V. Vernon(实施DDD)这本书,并且在第14章(第522页)中谈到(正确的)

我注意到他没有任何DTO使用命令.

someCommand.setId("id");
someCommand.setWeightValue("80");
someCommand.setWeightUnit("kg");
someCommand.setOtherWeight("80 kg");
someCommand.setDate("17/03/2015 17:28:35");
someCommand.setUserName("...");
someCommand.setUserAttribute("...");
someCommand.setUserOtherAttributePartA("...");
someCommand.setUserOtherAttributePartB("...");

它是由控制器映射的命令对象.值对象初始化将在命令处理程序方法中得到应用,并且它们会在错误值(初始化时进行自验证)时抛出异常.

我觉得我开始不太在意,但其他一些意见也会受到欢迎.

作为介绍,这是非常有意见的,我相信每个人都有不同的想法,如何运作.但是我在这里的努力是为了勾勒出有一些很好的理由的战略,所以你可以做出自己的评估.

通过字符串或解析?

我个人的喜好是解析控制器中的所有内容,并将结果发送给服务.这种方法有两个主要阶段,每个阶段都可以回溯错误条件:

尝试解析

当一串字符串从UI进入时,我认为尝试立即解释它是有意义的.对于像int和bools这样的简单目标,这些转换是微不足道的,许多Web框架的模型绑定可以自动处理它们.

对于更复杂的对象(如自定义类),在此位置处理它仍然有意义,以便所有解析都发生在同一位置.如果您在提供模型绑定的框架中,大部分此解析可能会自动完成;如果没有 – 或者您正在组装一个更复杂的对象发送到服务 – 您可以在控制器中手动执行.

故障条件

解析失败(在“int”字段中输入“hello”或为bool输入“7”),在您甚至必须调用该服务之前,很容易向用户发送反馈.

2.验证并提交

即使解析成功,仍然有必要验证该条目是否合法,然后提交.我更喜欢在提交之前立即在服务级别处理验证.这使得控制器负责解析,并在代码中非常清楚地确认每个提交的数据的验证.

在这方面,我们可以从服务层消除辅助责任.没有必要使它解析对象 – 其单一目的是提交信息.

故障条件

当验证失败(有人在月球上输入地址,或者在过去300年内输入出生日期)时,应该将故障报告给调用方(在这种情况下为Controller).虽然用户可能无法区分解析失败和无法验证,但这对软件是一个重要的区别.

将值对象推送到UI?

我会尽可能接受解析的对象尽可能多的堆栈.如果你可以让别人的框架处理这一点转变,为什么不这样做?此外,更接近对象可以存在的UI,向用户提供关于他们正在做什么的良好,快速的反馈越容易.

关于耦合的注意事项

总的来说,将物体推入堆栈确实会导致更大的耦合.然而,为特定领域编写软件确实涉及紧密耦合到该域,无论它是什么.如果还有一些组件与整个域中无处不在的概念紧密耦合,或者至少是被称为服务的API接触点,我看不出任何真正的架构完整性或灵活性的降低.

解析一个大字符串或组件?

一般来说,将整个字符串传递到Parse()方法中往往是最简单的,以便进行排序.以“80公斤”为例:

>“80公斤”和“120磅”都可以是有效的重量输入>如果你传递一个字符串到一个Parse()方法,它可能是做一些相当沉重的举重.期望它根据空间分割一个字符串不是过分的.调用Weight.create(inputString)比将“input”分割为“”更容易,然后调用Weight.create(split [0],split [1]).>保持单串输入的Parse()函数也很容易.如果有一些新的要求,重量级别必须支持磅和盎司,新的有效输入可能是“120磅6盎司”.如果你分开输入,你现在需要四个参数.而如果它完全封装在Parse()逻辑中,那么外部消费者就没有任何负担.这使得代码更加可扩展和灵活.

猜你在找的设计模式相关文章