需要在 3 层架构的服务中使用域模型吗?
Need for a domain model in a service in 3 tier architecture?
我正在构建一个 API Rest with Spring Boot,我想澄清一个关于我的架构的概念,看看社区是否可以帮助我。
假设在我的数据库中有一个名为 Person
的 table。我正在安装基于三层架构的架构。总体方案如下:
一方面,我有 PersonDao.java
,它将负责访问数据库以从 Person
table 中检索元组。为此,它使用名为 PersonEntity.java
的 class,它包含(作为属性)table 的所有列。 PersonDao.java
将 return 来自 PersonModel.java
class 的对象。 PersonModel.java
是代表 Person
商业模式的 class。
另一方面,我有 PersonService.java
,它负责执行我的应用程序的业务逻辑。此服务调用 PersonaDao.java
以访问存储在数据库中的信息。 PersonService.java
使用 PersonModel.java
class 的对象,因为这个 class 代表我的应用程序的业务对象。 PersonService.java
将永远 return 一个 PersonDto,java
.
最后,PersonController.java
。该控制器将是公开 Rest API 连接接口的控制器。他总是使用 DTO 并通过 DTO 与 PersonService.java
通信。
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
层中的使用。 (因此 presentation
和 data
层不是问题的一部分)。
关于PersonModel
我不确定你对 PersonModel
的意思以及它的实际作用,但乍一看我可以说你通常不需要这样的东西,这只会增加额外的代码重复和迟早会有维护开销。
关于PersonDto
顾名思义,DTO
s 实际上是用于在客户端(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 domain 和 data
层的 真实 实体(例如 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]
我正在构建一个 API Rest with Spring Boot,我想澄清一个关于我的架构的概念,看看社区是否可以帮助我。
假设在我的数据库中有一个名为 Person
的 table。我正在安装基于三层架构的架构。总体方案如下:
一方面,我有
PersonDao.java
,它将负责访问数据库以从Person
table 中检索元组。为此,它使用名为PersonEntity.java
的 class,它包含(作为属性)table 的所有列。PersonDao.java
将 return 来自PersonModel.java
class 的对象。PersonModel.java
是代表Person
商业模式的 class。另一方面,我有
PersonService.java
,它负责执行我的应用程序的业务逻辑。此服务调用PersonaDao.java
以访问存储在数据库中的信息。PersonService.java
使用PersonModel.java
class 的对象,因为这个 class 代表我的应用程序的业务对象。PersonService.java
将永远 return 一个PersonDto,java
.最后,
PersonController.java
。该控制器将是公开 Rest API 连接接口的控制器。他总是使用 DTO 并通过 DTO 与PersonService.java
通信。
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
层中的使用。 (因此 presentation
和 data
层不是问题的一部分)。
关于PersonModel
我不确定你对 PersonModel
的意思以及它的实际作用,但乍一看我可以说你通常不需要这样的东西,这只会增加额外的代码重复和迟早会有维护开销。
关于PersonDto
顾名思义,DTO
s 实际上是用于在客户端(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 domain 和 data
层的 真实 实体(例如 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 中手动完成,但通常
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]