在不同层之间拥有一些包并不罕见,但是通常仅用于横切问题,例如日志记录。您的模型不应由不同的层共享,否则对模型的更改将需要更改所有这些层。通常,模型是靠近数据层的下层(上方、下方或交织在一起,具体取决于方法)。
数据传输对象,顾名思义,是用于传输数据的简单类。因此,它们通常用于层之间的通信,特别是当您有一个通过消息而不是对象进行通信的SOA架构时。DTO应该是不可变的,因为它们只是为了传输信息而存在,而不是为了改变信息。
您的域对象是一回事,DTO 是另一回事,而表示层中需要的对象是另一回事。但是,在小型项目中,可能不值得努力实现所有这些不同的集合并在它们之间进行转换。这完全取决于您的要求。
您正在设计一个Web应用程序,但问问自己“我可以通过桌面应用程序切换我的Web应用程序吗?我的服务层真的不知道我的表示逻辑吗?从这些角度思考将引导您走向更好的架构。
关于您的问题:
假设持久性层将使用类 myproject.persistence.domain.UserEntity(基于 JPA 的实体)来存储数据并将其加载到数据库/从数据库加载数据。为了在视图中显示数据,我将提供另一个类myproject.service.domain.User。我在哪里转换它们?用户的服务是否负责在两个类之间进行转换?这真的有助于改善耦合吗?
服务层知道它的类 (DTO) 和它下面的层(假设持久性)。所以,是的,该服务负责在持久性和自身之间进行转换。
用户类的外观应该如何?它应该只包含不可变的 getter 吗?视图编辑现有用户(创建新用户,使用现有 User 对象的 getter 等)不是很麻烦吗?
DTO 背后的想法是,您只能将它们用于传输,因此不需要创建新用户等操作。为此,您需要不同的对象。
我应该使用相同的 DTO 类(用户)向服务发送请求以修改现有用户/创建新用户,还是应该实现其他类?
服务方法可能表示操作,DTO 是其仅包含数据的参数。另一种选择是使用表示操作并包含 DTO 的命令。这在 SOA 体系结构中很流行,其中您的服务可能只是一个命令处理器,例如,有一个以接口为参数的单个操作(而不是每个命令有一个操作)。Execute
ICommand
通过使用 myproject.service.domain 中的所有 DTO,表示层不是非常依赖于服务层吗?
是的,服务层上的层将依赖于它。这就是我们的想法。好处是只有该层依赖于它,没有上层或下层,因此更改仅影响该层(与从每个层使用域类时发生的情况不同)。
如何处理我自己的异常?我目前的方法会重新抛出大多数“严重”异常,直到它们由表示层处理(通常它们被记录下来,并且用户被告知出了问题)。一方面,我有一个问题,我再次遇到一个共享包。另一方面,我仍然不确定这是否可被视为“最佳做法”。有什么想法吗?
每个层都可以有自己的例外。它们从一层流向另一层,封装在下一种异常中。有时,它们将由一个层处理,该层将执行某些操作(例如日志记录),然后可能引发上层必须处理的不同异常。其他时候,它们可能会被处理,问题可能会得到解决。例如,考虑连接到数据库的问题。这将引发异常。您可以处理它并决定在一秒钟后重试,然后可能会有成功,因此异常不会向上流动。如果重试也失败,则将重新引发异常,并且它可能会一直流到表示层,您可以在其中优雅地通知用户并要求他重试层。