java—当您拥有与pojo(实体)相同的对象时,让dto对象有什么意义?

wi3ka0sx  于 2021-07-06  发布在  Java
关注(0)|答案(4)|浏览(432)

我想了解当您已经拥有pojo对象(作为实体)时,创建dto对象有什么好处。
在我的项目中,我有两个:
dto类用于在web服务和应用程序之间进行通信
pojo实体类(jpa)用于数据库和应用程序之间的通信
如果我看一个dto对象类(我们称之为myobjdto)和同一个类,但是pojo方面(我们称之为myobjpojo),除了myobjpojo作为注解外,没有任何区别,因为它是一个@entity。
所以事实上,我在我的项目中有两个类,它们看起来相同(相同的属性,相同的方法),但是用于不同的对象。
在这种情况下,dto类是无用的,并且增加了应用程序的复杂性,因为我对dto类所做的一切都可以用pojo类来完成,而且,对于单一类型的对象,我必须维护至少2个类(dto和pojo),例如,如果我添加一个属性,我必须在这两个类中都添加这个属性。
我不是Maven,我在质疑我的想法;你觉得怎么样?

lymnna71

lymnna711#

其他人已经告诉您dto的好处,这里我将讨论如何解决维护一个以上dto版本对象的问题。我开发了一个库beanknife来自动生成一个dto。它将在原始pojo的基础上创建一个新的类。您可以筛选继承的属性、修改现有属性或添加新属性。您只需要编写一个配置类,库就会为您完成剩下的事情。配置支持继承特性,因此您可以提取公共部分来简化配置。下面是一个例子

@Entity
class Pojo1 {
   private int a;
   @OneToMany(mappedBy="b")
   private List<Pojo2> b;
}

@Entity
class Pojo2 {
   private String a;
   @ManyToOne()
   private Pojo1 b;
}

// Include all properties. By default, nothing is included.
// To change this behaviour, here use a base configuration and all other final configuration will inherit it.
@PropertiesIncludePattern(".*")
// By default, the generated class name is the original class name append with "View",
// This annotation change the behaviour. Now class Pojo1 will generate the class Pojo1Dto
@ViewGenNameMapper("${name}Dto")
class BaseConfiguration {
}

// generate Pojo1Dto, which has a pojo2 info list b instead of pojo2 list
@ViewOf(value = Pojo1.class)
class Pojo1DtoConfiguration extends BaseConfiguration {
    private List<Pojo2Info> b;
}

// generate Pojo1Info, which exclude b
@ViewOf(value = Pojo1.class, genName="Pojo1Info", excludes = "b")
class Pojo1InfoConfiguration extends BaseConfiguration {}

// generate Pojo2Dto, which has a pojo1 info b instead of pojo1
@ViewOf(value = Pojo2.class)
class Pojo2DtoConfiguration extends BaseConfiguration {
    private Pojo1Info b;
}

// generate Pojo2Info, which exclude b
@ViewOf(value = Pojo2.class, genName="Pojo2Info", excludes = "b")
class Pojo2InfoConfiguration extends BaseConfiguration {}

将生成

class Pojo1Dto {
   private int a;
   private List<Pojo2Info> b;
}

class Pojo1Info {
   private int a;
}

class Pojo2Dto {
   private String a;
   private Pojo1Info b;
}

class Pojo2Info {
   private String a;
}

那就这样用吧

Pojo1 pojo1 = ...
Pojo1Dto pojo1Dto = Pojo1Dto.read(pojo1);
Pojo2 pojo2 = ...
Pojo2Dto pojo2Dto = Pojo2Dto.read(pojo2);
5sxhfpxr

5sxhfpxr2#

这个答案是可以在堆栈交换上找到的内容的副本。imho的评论应该被关闭,因为被张贴在错误的论坛。它目前也吸引了一些固执己见的答案,尽管不一定如此,而且与java没有任何特定的联系。
dto是一种模式,它独立于实现(pojo/poco)。dto说,由于对任何远程接口的每个调用都是昂贵的,所以对每个调用的响应应该带来尽可能多的数据。因此,如果需要多个请求来为特定任务带来数据,那么可以将要带来的数据合并到一个dto中,这样只有一个请求可以带来所有需要的数据。企业应用程序体系结构的模式目录有更多的细节。
dto是一个基本概念,而不是过时的概念。
有些过时的概念是,DTO完全不包含逻辑,只用于传输数据,在传输到客户机之前从域对象“Map”,并在将其传递到显示层之前Map到视图模型。在简单的应用程序中,域对象通常可以直接重用为dto并直接传递到显示层,因此只有一个统一的数据模型。对于更复杂的应用程序,您不希望向客户机公开整个域模型,因此需要从域模型到dto的Map。拥有一个从dto复制数据的独立视图模型几乎毫无意义。
然而,这个概念过时而不是完全错误的原因是一些(主要是较旧的)框架/技术需要它,因为它们的域和视图模型不是pojo,而是直接与框架绑定。
最值得注意的是,在EJB3标准之前的j2ee中,实体bean不是POJO,而是由应用程序服务器构造的代理对象—根本不可能将它们发送到客户端,因此您没有选择要将一个单独的dto层—这是必须的。
虽然dto不是一个过时的模式,但它经常被不必要地应用,这可能会使它看起来过时。
来自java大师adam bien:
java企业社区中最被误用的模式是dto。dto被明确定义为一个分配问题的解决方案。dto本来是一个粗粒度的数据容器,可以有效地在进程(层)之间传输数据亚当宾
来自martin fowler:
DTO被称为数据传输对象,因为它们的全部目的是在昂贵的远程调用中转移数据。它们是实现粗粒度接口的一部分,远程接口需要粗粒度接口来提高性能。不仅仅是在本地环境中不需要它们,它们实际上是有害的,因为粗粒度的api更难使用,而且您必须完成将数据从域或数据源层移动到DTO的所有工作马丁福勒
下面是一个javaee特定的示例,说明dto模式的常见但不正确的用法。如果您不熟悉javaee,您只需要了解mvc模式:“jsf managedbean”是视图使用的类,“jpa entity”是mvc模式中的模型。
例如,假设您有一个jsf managedbean。一个常见的问题是bean是应该直接持有对jpa实体的引用,还是应该维护对某个中介对象的引用,该中介对象后来被转换为实体。我听说这个中介对象被称为dto,但是如果managedbeans和实体在同一个jvm中运行,那么使用dto模式没有什么好处。
此外,考虑bean验证注解(同样,如果您不熟悉javaee,请知道bean验证是验证数据的api)。您的jpa实体可能带有@notnull和@size validations注解。如果您使用的是dto,则需要在dto中重复这些验证,这样使用远程接口的客户机就不需要发送消息来发现他们的基本验证失败。想象一下在dto和实体之间复制bean验证注解的所有额外工作,但是如果您的视图和实体在同一个jvm中运行,就不需要承担这些额外工作:只使用实体。
企业应用程序体系结构模式目录提供了DTO的简明解释,下面是我发现的更多有启发性的参考资料:
如何处理j2ee和设计模式
如何在jsf+spring+hibernate中使用dto
fowler描述dto中数据传输对象的优缺点
martin fowler解释了DTO的问题。显然,早在2004年它们就被滥用了

9q78igpj

9q78igpj3#

其中大部分归结为干净的体系结构和关注点分离
对于实体,我最大的用例是这样我就不会在dto中乱扔为了方便而添加的运行时变量或方法(比如显示名称/值或post计算值)
如果它是一个非常简单的实体,那么就没有什么大不了的,但是如果你对clean非常严格,那么就会有很多冗余模型(dto,dbo,entity)
它实际上是一个偏好,在多大程度上你想致力于严格干净的架构
https://medium.com/android-dev-hacks/detailed-guide-on-android-clean-architecture-9eab262a9011

j5fpnvbx

j5fpnvbx4#

即使很小,在您的体系结构中有一个分离的层,并且让对象在层中移动时“变形”也是有好处的。这种解耦允许您以最小的更改替换软件中的任何层,只需更新2个对象和所有集合之间的字段Map即可。
如果这两个对象具有相同的成员…那么这就是apache commons beanutils.copyproperties()的作用;)

相关问题