在不同层之间放置一些软件包并不少见,但是通常只能用于跨层次关注,例如日志记录.您的模型不应该被不同的层共享,或者模型的更改将需要所有这些层的更改.通常情况下,您的模型是较低的层,靠近数据层(根据方法,在,下或下交错).

数据传输对象,正如其名称所暗示的,是用于传输数据的简单类.因此,它们通常用于层之间的通信,特别是当您具有通过消息而不是对象进行通信的SOA架构时. DTO应该是不可变的,因为它们仅仅是为了传递信息而不是改变信息而存在的.

您的域对象是一回事,您的DTO是不同的,您在表示层中需要的对象是另一回事.然而,在小型项目中,实施所有这些不同的集合并在其间进行转换可能不值得.这只是取决于你的要求.

您正在设计一个Web应用程序,但它可能会帮助您的设计问自己,“我可以通过桌面应用程序切换我的Web应用程序吗?我的服务层真的不知道我的演示逻辑吗?以这些方式思考,将引导您走向更美好的建筑.

关于你的问题:

Assume the persistence layer would use a class myproject.persistence.domain.UserEntity (a JPA based entity) to store and load data to/from the database. To show data in the view I would provide another class myproject.service.domain.User. Where do I convert them? Would the service for the users be responsible to convert between the two classes? Would this really help to improve the coupling?

服务层知道它的类(DTO)和它下面的层(我们说持久性).所以是的,这个服务负责在持久性和本身之间进行翻译.

How should the User class look like? Should it contain only getters to be immutable? Wouldn’t it be cumbersome for the views to edit existing users (create a new User, use the getters of the existing User object etc.)?

DTO背后的想法是您只将其用于传输,因此不需要创建新用户等操作.为此,您需要不同的对象.

Should I use the same DTO-classes (User) to send a request to the service to modify an existing user/create a new user or should I implement other classes?

服务方式可能表示操作,DTO是仅包含数据的参数.另一个选择是使用表示操作的命令,并且还包含DTO.这在SOA架构中很受欢迎,其中您的服务可能仅仅是一个命令处理器,例如具有一个单独的Execute操作将ICommand接口作为参数(而不是每个命令有一个操作).

Wouldn’t the presentation layer be very dependent on the service layer by using all the DTOs in myproject.service.domain?

是的,服务层上的层将依赖于它.这是想法.上层是只有该层依赖于它,没有上层或下层,所以更改仅影响该层(不同于如果您使用每个层的域类)会发生什么.

How to handle my own exceptions? My current approach rethrows most “severe” exceptions until they are handled by the presentation layer (usually they are logged and the user is informed that something went wrong). On the one hand I have the problem that I hava again a shared package. On the other hand I am still not sure that this can be considered “best practice”. Any ideas?

每层都有自己的例外.它们从一层流向另一层,封装到下一种异常中.有时,它们将由一层执行某些操作(例如记录),然后抛出上层必须处理的不同异常.其他时候,他们可能被处理,问题可能得到解决.想想连接到数据库的问题的实例.它会抛出异常.你可以处理它,并决定重新尝试一秒钟,也许然后有成功,因此异常不会向上流动.如果重试也失败,则将重新抛出异常,并且可能会一直运行到您优雅地通知用户并请他重试层的表示层.