如何使用和创建 DTO 是 OOP 的世界?
How to use and create DTOs is OOP world?
- 从业务对象创建 DTO 的正确方法是什么?
- 谁应该负责创建它们? BO/DTO 本身来自 BO/some 静态工厂?
- 如果我有,它们应该驻留在代码中的什么地方,f.e。我需要 DTO 的一些核心库和特定服务 API 库?在 BO 旁边的核心库中(这似乎不正确)/在特定库中?
- 如果我在我的 BO 中封装了字段,DTO 如何获取它们? (显然,如果 BO 不负责创建 DTO)
举个例子,假设我有这样的 Person BO:
class Person
{
private int age;
public bool isBigEnough => age > 10;
}
我希望 age
成为 Person
的内部状态,但我仍然需要将我的 BO 传达给某些 api。或者在我的 class 中有私人字段,我想发送到某个地方已经意味着它应该是 public?
- 对于如何将 DTO 与带有封装数据的业务 classes 一起使用,是否有任何一般性考虑?
___更新:
除了@Alexey Groshev 提到的方法之外,我还遇到了另一种方法:我们将 BO class 的数据分离到一些具有 public 访问器的数据 class 中。 BO 用它的 api(可能使用组合)包装这个数据,并且在需要时它可以 return 它的状态作为数据 class 作为克隆。所以 dto 转换器将能够访问域对象的状态但不能修改它(因为它只是一个副本)。
我认为问题 5 的答案也将解决其他问题。
Are there any general considerations of how to use DTOs alongside business classes with encapsulated data?
请记住,DTO 仅用于传输数据。不要担心在 DTO 中实施任何类型的规则。它的全部用途是将数据从一个子系统移动到另一个子系统(不是在同一子系统的 类 之间)。数据在目标系统中的使用方式不受您的控制——尽管作为上帝程序员,您天生就知道它将如何使用,但不要让这些知识影响您的设计——因此不应该表达任何假设作为行为或知识访问者——所以,没有 isBigEnough
.
有多种选择,但很难推荐任何东西,因为我不知道你的 project/product 的详细信息。不管怎样,我会举几个例子。
可以使用AutoMapper to map BOs to DTOs and vise versa. I personally dislike this approach, because it's quite difficult (but possible) to keep it under control in medium/large sized projects. People don't usually bother to configure mappings properly and just expose internal state of their objects. For example, your isBigEnough
would disappear and age
would become public
. Another potential risk is that people can map DTOs to/from EF/Hibernate objects. You can find some articles which explain why it's considered to be a bad practice.
按照您的建议,BO可以自己创建DTO,但是您将如何实现这种方法?您可以向实体添加方法或工厂方法,例如public PersonDto ToDto()
。或者您可以添加一个接口,例如public interface IDtoConvertable<T> { T ToDto(); }
,并选择哪个实体或聚合根将实施它。您的 Person
class 看起来像这样 class Person : IDtoConvertable<PersonDto> {... public PersonDto ToDto() {...} }
。在这两种情况下,DTO namespace/assembly 必须可供实体访问,这有时可能是个问题,但通常不是什么大问题。 (确保 DTO 无法访问更糟糕的实体。)
(C#) 另一种选择是 return 创建 DTO 的委托。我决定将它与 (2) 分开,因为实体本身并没有真正创建 DTO,而是公开了创建 DTO 的功能。所以,你可以有这样的东西 public Func<PersonDto> ToDto() {...}
。您可能想要一个如 (2) 中的界面,但您明白了,不是吗?我喜欢这种方法吗?不,因为它使代码不可读。
如您所见,问题多于答案。我建议您做一些实验,看看哪些对您(您的项目)有效,哪些无效。
- 从业务对象创建 DTO 的正确方法是什么?
- 谁应该负责创建它们? BO/DTO 本身来自 BO/some 静态工厂?
- 如果我有,它们应该驻留在代码中的什么地方,f.e。我需要 DTO 的一些核心库和特定服务 API 库?在 BO 旁边的核心库中(这似乎不正确)/在特定库中?
- 如果我在我的 BO 中封装了字段,DTO 如何获取它们? (显然,如果 BO 不负责创建 DTO)
举个例子,假设我有这样的 Person BO:
class Person
{
private int age;
public bool isBigEnough => age > 10;
}
我希望 age
成为 Person
的内部状态,但我仍然需要将我的 BO 传达给某些 api。或者在我的 class 中有私人字段,我想发送到某个地方已经意味着它应该是 public?
- 对于如何将 DTO 与带有封装数据的业务 classes 一起使用,是否有任何一般性考虑?
___更新:
除了@Alexey Groshev 提到的方法之外,我还遇到了另一种方法:我们将 BO class 的数据分离到一些具有 public 访问器的数据 class 中。 BO 用它的 api(可能使用组合)包装这个数据,并且在需要时它可以 return 它的状态作为数据 class 作为克隆。所以 dto 转换器将能够访问域对象的状态但不能修改它(因为它只是一个副本)。
我认为问题 5 的答案也将解决其他问题。
Are there any general considerations of how to use DTOs alongside business classes with encapsulated data?
请记住,DTO 仅用于传输数据。不要担心在 DTO 中实施任何类型的规则。它的全部用途是将数据从一个子系统移动到另一个子系统(不是在同一子系统的 类 之间)。数据在目标系统中的使用方式不受您的控制——尽管作为上帝程序员,您天生就知道它将如何使用,但不要让这些知识影响您的设计——因此不应该表达任何假设作为行为或知识访问者——所以,没有 isBigEnough
.
有多种选择,但很难推荐任何东西,因为我不知道你的 project/product 的详细信息。不管怎样,我会举几个例子。
可以使用AutoMapper to map BOs to DTOs and vise versa. I personally dislike this approach, because it's quite difficult (but possible) to keep it under control in medium/large sized projects. People don't usually bother to configure mappings properly and just expose internal state of their objects. For example, your
isBigEnough
would disappear andage
would becomepublic
. Another potential risk is that people can map DTOs to/from EF/Hibernate objects. You can find some articles which explain why it's considered to be a bad practice.按照您的建议,BO可以自己创建DTO,但是您将如何实现这种方法?您可以向实体添加方法或工厂方法,例如
public PersonDto ToDto()
。或者您可以添加一个接口,例如public interface IDtoConvertable<T> { T ToDto(); }
,并选择哪个实体或聚合根将实施它。您的Person
class 看起来像这样class Person : IDtoConvertable<PersonDto> {... public PersonDto ToDto() {...} }
。在这两种情况下,DTO namespace/assembly 必须可供实体访问,这有时可能是个问题,但通常不是什么大问题。 (确保 DTO 无法访问更糟糕的实体。)(C#) 另一种选择是 return 创建 DTO 的委托。我决定将它与 (2) 分开,因为实体本身并没有真正创建 DTO,而是公开了创建 DTO 的功能。所以,你可以有这样的东西
public Func<PersonDto> ToDto() {...}
。您可能想要一个如 (2) 中的界面,但您明白了,不是吗?我喜欢这种方法吗?不,因为它使代码不可读。
如您所见,问题多于答案。我建议您做一些实验,看看哪些对您(您的项目)有效,哪些无效。