结合DDD,多种实现和REST

时间:2014-11-01 15:37:08

标签: java rest inheritance domain-driven-design encapsulation

我在设计一个将Domain Driven Desing原则与REST相结合的应用程序的架构时遇到了问题。对我来说,最大的问题是Domain只是接口规范和响应实体。当然,我可以随意改变这个共同层,但是现在这个想法。我需要这个公共层,因为我希望能够将许多实现中的一个插入基于域的接口。

所以来了:

  • 有不同的业务流程引擎
  • 为了拥有所有这些API的通用API,我需要将它们包装在我的包装类中,这将实现我的接口
  • 我希望我的包装器具有良好的封装(因为DDD显示它 - 不公开其内部细节)
  • 我还希望能够通过REST公开我的域对象,这是最大的问题:

选项1 :我可以将封装与REST结合使用经典对象(只需公开暴露行为的公共方法和@JsonProperty注释的私有字段),但我需要接口(或者我可以使用抽象类) ,那里你不能拥有私有的继承字段......

选项2 :我可以使用@JsonProperty注释的公共getter,但这会破坏封装

选项3 :所以我认为这里很好,至少从封装点来看是创建将要实现的不可变值对象(如果你可以说那组公共字段是一个实现)在公共层中,将用作域对象上调用的特定方法的输入和输出。这是一个不错的选择吗?我不知道......它似乎运作良好,不会制动封装原理

我认为它基本上解释了我的问题。我认为对REST API有用的是使用Restlet对象,但是对于我来说,围绕Restlet对象是一个问题,实际上是由不同的实现类实现的接口......

我附上了一些基本的架构图,也许它会帮助你理解我的问题: Architecture outline

2 个答案:

答案 0 :(得分:1)

我在一个更复杂的企业应用程序上拥有基本相同的架构。我通过创建" JAXB值对象"来解决这个问题。使用JAXB(+ jackson,如果你愿意)注释,定义了我希望从JAX-RS端点看到的XML / JSON格式。我基本上使用了一个适配器模式,所以我可以将这些值对象视为实现,并在这些值对象上添加了一个工厂方法,这样我就可以根据需要进行复制(有时很深)。偏离#3的一件事是我没有使我的JAXB值对象不可变(尽管接口看起来是不可变的),因为JAXB真的不喜欢这样。如果我将这些JAXB值对象传递给另一个组件(我不会),我会先做一个防御性的副本。

除了保持我的域建立在接口(JAXB真的不喜欢)之外,这对于你提到的不同实现很重要,它还允许我在我需要时定义不同的JAXB值对象不同的观点"定义。

答案 1 :(得分:1)

我已经向朋友建筑师提出了这个问题,这就是他给我写的:

让我们想想什么是REST? REST只是一个表示层,它在系统上公开一个视图。它已经在系统和它的表示之间划出了一个区别(系统边界),我们这里有不同职责的经典问题。我坚信“价值就是制度边界”。我不会公开域对象,而是创建值对象,这些对象是从域对象转换到域对象的。这意味着创建一大堆值对象,这些对象代表REST层的各个资源。当然,如果你在Java世界中,它意味着创建类,有getter和setter,但它绝对值得。我可能听起来像法西斯主义者,但我会在域和它的表示之间绘制清晰的边界,你只需要很好的映射层(有很多这些),但我不想在JAXRS端点(资源)中看到域对象。通过这种方式,您可以在您和用于BPM的其他第三方框架之间创建防反应层,因此简而言之,这意味着这些框架中的升级和更改将受您的控制。所以我认为你正朝着正确的方向前进,但不会在JAXRS中使用域类,并创建Value Objects。

我需要构建以下图层。 BPM引擎 - >通用界面(在我的理解中看起来像DDD的策略) - >由根聚合构建的VO对象(您需要一种方法来对这些对象进行分解),VO应该具有JSON映射注释,而不是通用接口 - >访问根聚合的JAXRS,从它们获取VO - >杰克逊做了映射的魔力

因此,您可以拥有稳定的界面,每次系统内部发生变化时,您都不希望重建REST层。所以VO在这里隐藏你的内部接口(通用接口)的变化。如果我错了,请纠正我,但是你想创建一种常见的BPM引擎最低分母,拥有相同的模型,尽管Activit和jBPM模型存在差异。

我认为JAXRS应该是非常薄的层,在我工作的应用程序中,在几个地方我们开始添加一些逻辑,你知道截止日期,在一天结束时,一切都在我们的脸上爆炸,当人们没有'知道在JAXRS中应用了一些额外的规则,重构是噩梦。最后,我们转移到JAXRS刚刚到达的模型,聚合根/实体请求VO并将其返回。