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