如何使用和创建DTO是OOP世界?

时间:2016-06-06 14:54:04

标签: oop design-patterns dto

  1. 从业务对象创建DTO的正确方法是什么?
  2. 谁应该负责创建它们? BO / DTO本身来自BO /一些静态工厂?
  3. 如果我有,他们应该驻留在代码中,例如一些核心库和我需要DTO的特定服务API库?在BO旁边的核心库(似乎不正确)/在特定库中?
  4. 如果我在BO中有封装字段,DTO如何抓住它们? (显然,如果BO不负责创建DTO)
  5. 作为一个例子,假设我有一个像这样的Person BO:

    class Person
    {
        private int age;
        public bool isBigEnough => age > 10;
    }
    

    我希望age成为Person的内部状态,但我仍然需要将我的BO传达给某个api。或者在我的班级中有私人领域,我想发送到某个地方已经意味着它应该是公开的?

    1. 对于如何将DTO与业务类一起用于封装数据,是否有任何一般性考虑因素?
    2. ___更新:

      除了@Alexey Groshev提到的方法之外,我还遇到了另一种方法:我们将BO类的数据分成一些带有公共访问器的Data类。 BO用它的api(可能使用组合)包装这些数据,并且在需要时它可以将其状态作为Data类返回为clone。因此,dto转换器将能够访问Domain对象的状态,但无法修改它(因为它只是一个副本)。

2 个答案:

答案 0 :(得分:1)

有多种选择,但很难推荐任何内容,因为我不了解您的项目/产品的详细信息。无论如何,我只列举一些。

  1. 您可以使用AutoMapper将BO映射到DTO,反之亦然。我个人不喜欢这种方法,因为在中型/大型项目中控制它是非常困难的(但可能的)。人们通常不愿意正确配置映射,只是暴露其对象的内部状态。例如,您的isBigEnough将消失,age将变为public。另一个潜在的风险是人们可以将DTO映射到EF / Hibernate对象/从EF / Hibernate对象映射。你可以找到一些文章解释为什么它被认为是bad practice

  2. 如你所知,BO可以自己创建DTO,但是你如何实现这种方法呢?您可以向实体添加方法或工厂方法,例如public PersonDto ToDto()。或者您可以添加一个界面,例如public interface IDtoConvertable<T> { T ToDto(); },并选择实现它的实体或聚合根。您的Person课程将如下class Person : IDtoConvertable<PersonDto> {... public PersonDto ToDto() {...} }。在这两种情况下,DTO命名空间/程序集必须可由实体访问,这有时可能是一个问题,但通常它不是一个大问题。 (确保DTO无法访问更糟糕的实体。)

  3. C#)另一种选择是返回创建DTO的委托。我决定将它与(2)分开,因为实体本身并没有真正创建DTO,而是暴露了创建DTO的功能。所以,你可能会有这样的事情public Func<PersonDto> ToDto() {...}。您可能希望拥有(2)中的界面,但是您明白了,不是吗?我喜欢这种方法吗?不,因为它使代码不可读。

  4. 如您所见,问题多于答案。我建议你做一些实验,检查一下对你(你的项目)有什么作用,以及什么不适合。

答案 1 :(得分:0)

我认为问题5的答案也将解决其他问题。

  

对于如何将DTO与业务类一起用于封装数据,是否有任何一般性考虑因素?

请记住,DTO仅用于传输数据。不要担心在DTO中实施任何类型的规则。它用于将数据从一个子系统移动到另一个子系统(不在同一子系统的类之间)。如何在目标系统中使用这些数据是你无法控制的 - 虽然作为上帝程序员你本身就知道它将如何被使用,但是不要让这些知识影响你的设计 - 因此不应该表达任何假设作为行为或知识访问者 - 所以,没有isBigEnough