我们的团队有一个基本上是MIS的项目。 我们使用的架构是带有DDD(域驱动设计)的CQRS。 我们在持久层中有持久性对象,域层中有域对象,数据传输对象用于携带用户的输入信息,查看对象以在特定页面上显示数据。
我认为这种设计很棒。但在实施项目期间,我们发现一些问题阻碍了我们。最令人作呕的是我们必须编写许多转换器来转换两个不同层之间的对象,如PO到DO,DO到PO,DTO到DO。这些转换器中的get和set语句太多了。我们之所以不使用像BeanUtils这样的东西,是因为当两个对象中的字段具有不同的类型或名称时,它不能很好地工作。显然,这些代码违反了开放 - 封闭原则。每当特定页面发生变化或我们想要更改数据库中的字段时,这将是一场噩梦。
我想知道它是否真的必须将DO和Po分开,我们可以简单地简化架构和设计以使它们相同,因为在大多数情况下它们只包含相同的字段而几乎没有差别。 我们如何简化设计以避免我们面临的问题并提高我们的生产力并确保软件的可扩展性和稳定性?
答案 0 :(得分:2)
如果你看看DDD战术模式,你将找不到“域对象”。您有聚合,如果您聚合根,则由实体和其中一个实体组成。每个有界上下文可能只有一个实体,这将是您的聚合根。
您将整个聚合体保留下来。基本存储库以“集合样式”运行,允许您只将新聚合放入存储库,并通过其标识从存储库中检索一个聚合。
CQRS将一个对象拆分为两个。一个对象是针对写入优化的聚合。通常,只需在“写入端”上的命令处理程序中使用集合式存储库就足够了。但是,在“阅读方面”,您拥有更平坦的阅读模型,这些模型代表您希望以优化阅读的方式向用户展示的内容。
如果您说您使用CQRS但只有一个模型和一个数据库,那么这没有多大意义。如果您有命令处理程序,则并不意味着您使用CQRS。
在澄清之后,我们可以看一下聚合持久性。 没有人说你不能按原样坚持聚合。在某种程度上,如果你有一个合适的存储,这实际上是首选的方法。通常,ORM不是一个合适的存储,因为它会在您发现对象世界和关系数据库世界之间阻抗不匹配的地方产生摩擦。文档数据库更适合这种情况。 PostgreSQL JSONB功能也是一个不错的选择。
流程将是:
正如您所看到的,这里没有任何持久性“转换”的真实位置。如果你有一个适当的存储空间,那一切都很好。
但是,当您阅读时,您会收到来自客户的请求。然后,此请求将发送给某些查询提供程序,数据提供程序或您调用此类的任何内容有些人将所有这些查询放入他们的存储库,但只有当你不使用CQRS或至少有一个持久性模型而不是两个时,这才有效。
查询是幂等的,它们不会更改系统的状态,并且可以在没有后果的情况下运行多次,除非在未优化读取的情况下可以加载持久层。但是,没有必要在读取方面放置大量抽象。同时,您不应将聚合发送回查询您的域的客户端。您需要有一个代表客户视图模型的DTO以满足特定需求,而不是更少而不是更多。此DTO需要进行优化,以便尽快在客户端呈现,无需计算和转换。这基本上是CQRS建议您在阅读方面做的事情 - 准备您的数据以快速交付这些DTO。