需要在 3 层架构的服务中使用域模型吗?

Need for a domain model in a service in 3 tier architecture?

我正在构建一个 API Rest with Spring Boot,我想澄清一个关于我的架构的概念,看看社区是否可以帮助我。

假设在我的数据库中有一个名为 Person 的 table。我正在安装基于三层架构的架构。总体方案如下:

PersonController <-> (PersonDto) <-> PersonService <-> (PersonModel) <-> PersonDao <-> (PersonEntity) <-> DB

问题是:是否有必要使用 PersonModel.java class 以便 PersonService.java 仅适用于此 class 的对象?或者 PersonService.java 直接使用来自 class PersonEntity.java 的对象会更好吗?如果我这样做是为了保持单一职责的原则,使得每一层只与它范围内的对象一起工作。

如果回答是 PersonModel.java 必须要保持各层职责单一的原则。如果使用 JpaRepository 会有什么变化吗?如果我问这个问题,那是因为在许多教程和示例中我看到当使用 JpaRepository 时,服务直接与实体一起工作。在这种情况下,我们不应该创建一个 class 来表示服务的业务对象吗?

EDIT: 在这个问题的回答中(),我脑子里有意义的架构会有所体现,但肯定不是最正确的事情。我得出的结论是每一层都会使用它自己的对象。复制/粘贴答案:

Typically you have different layers:

  • A persistence layer to store data
  • Business layer to operate on data
  • A presentation layer to expose data

Typically, each layer would use its own kind of objects:

  • Persistence Layer: Repositories, Entities
  • Business Layer: Services, Domain Objects
  • Presentation Layer: Controllers, DTOs

This means each layer would only work with its own objects and never ever pass them to another layer.

提前致谢。

据我了解,您的问题特别是关于 及其在 logic 层中的使用。 (因此 presentationdata 层不是问题的一部分)。

关于PersonModel

我不确定你对 PersonModel 的意思以及它的实际作用,但乍一看我可以说你通常不需要这样的东西,这只会增加额外的代码重复和迟早会有维护开销。

关于PersonDto

顾名思义,DTOs 实际上是用于在客户端(presentation 层)和您的 API(controller / boundary logic tier) 中的层,用于公开 "client friendly" 您的 domain model, to regulate the over- and under-fetching - somehow (thanks to GraphQL 演示文稿,这现在几乎不再是问题)。因此,您的业务服务 classes 根本不需要了解或处理 DTO。

此外,正如您已经提到的,为了 SRP 业务或 dao classes 不应该处理额外的数据映射(例如 Dto <-> 模型、模型 <->实体)以任何方式。它们已经完成了逻辑层中的特定任务(参见边界层服务层)。

关于PersonEntity

这通常表示来自 problem domaindata 层的 真实 实体(例如 RDBMS 中的数据库 table或 NoSQL 中的文档)。所以这很常见

  • 实体 class 的命名没有后缀,例如 Entity。只需使用普通名称即可,例如Person,

  • 实体 classes 包含额外的注释(例如 JPA)以使它们对 ORM layer(例如 Hibernate)可见,

  • 实体 class 不一定 anemic 并且实际上包含一些额外的行为(可能是您想对 PersonModel class), 例如

class Person {
  Date birthday;

  int getAge() { /* calculate age based on the birthday */ }

  boolean isAdult() { /* getAge() >= 18 */ }
}

总结

用例:创建 Person 实体

Hinflug(去程航班)

[Client] --> (data: JSON) --> <Deserialization as `PersonDTO`> --> <DTO Validation> --> [PersonController] --> <AutoMapping to `Person` entity> --> [PersonService] --> [PersonDao] --> <ORM and JDBC> --> <Entity Validation> --> DB

注意:<Validation> 也可以在 Controller 中手动完成,但通常 is used to automate this process in the backgroud. The good thing is you can use the Bean Validation API to validate both your DTOs and the Entities (e.g. with Hibernate Validator)。

Rückflug(return航班)

DB --> <ORM and JDBC> --> [PersonDao] --> [PersonService] --> <AutoMapping to `Person` entity> --> [PersonController] --> <AutoMapping `Person` entity to `PersonDTO`>  --> <Serialization of `PersonDTO`> --> (data: JSON) -> [Client]