【问题标题】:Is there a "clean" way to replace all attribute values of an object in Java with values from another object of the same type?是否有一种“干净”的方法可以用来自另一个相同类型对象的值替换 Java 中对象的所有属性值?
【发布时间】:2021-11-29 02:21:24
【问题描述】:

先简单解释一下。 假设我们有一个方法,它将一个 Student 对象和一个 Id 作为属性,并使用传递的对象中包含的信息更新具有给定 Id 的学生。到目前为止,我找到的最简单的解决方案如下:

  1. 我们搜索我们的存储库以寻找我们想要更新的学生。
  2. 如果我们找到它,然后我们使用 setter 来设置新值。
    public void updateStudent(Long id, Student newStudent) {
        Student studentToBeUpdated = studentRepo
                .findStudentById(id)
                .orElseThrow(() ->
                        new UserNotFoundException("Student with id " + id + " was not found"));
        studentToBeUpdated.setFirstName(newStudent.getFirstName());
        studentToBeUpdated.setLastName(newStudent.getLastName());
        studentToBeUpdated.setEmail(newStudent.getEmail());
    }

所以,干得好,我们可以回家了,对吧? 好吧,现在假设我们的项目增长了很多,我们必须向 Student 类添加 20 多个属性。突然间,我们必须手动更新此方法以及执行类似操作的任何其他方法。不好。此外,我们刚刚创建了一些不好的样板代码。

我真正想要的是一种无需考虑我们的 Student 类有多少属性或这些属性是什么的方法,即使它们本身是枚举、数组甚至其他对象。我想要的是这样的:

studentToBeUpdated.replace(newStudent);

这是可能的还是只是我的一厢情愿?下一个最好的事情可能是创建一个可以由我自己完成所有这些的方法,但这仍然不是一个完美的解决方案,因为每次类属性更改时也必须对其进行编辑。

【问题讨论】:

  • 当属性被允许为基元以外的东西时,事情会变得很糟糕。好的,字符串也不难,因为它们是不可变的(并且其他不可变类型可能很容易处理)。但是对于其他类型的属性,首先要确定是否需要深拷贝。在深拷贝的情况下,必须考虑与原始类相同的考虑。最后,只有非常简单的类才能从这种“干净替换”的方式中受益。

标签: java object assign


【解决方案1】:

对于两个 Java 对象之间的映射,您可以使用 MapStruct 之类的东西,或者您可以编写自己的映射器,本质上是将样板代码提取到单独的类/服务中。

如果您决定创建自己的映射器,您可以使用reflection 或使用setter 方法或构建器模式(Lombok 的@Builder 也可以帮助避免编写构建器模式的样板)。

...现在假设我们的项目增长了很多,我们必须向 Student 类添加 20 多个属性。突然间,我们不得不手动更新此方法以及执行类似操作的任何其他方法。

当然,您的实体以及因此您的数据库的字段/列数会增加,但如果您提取不同类中的所有映射和转换,这通常不会有什么大不了的。在大多数情况下,无论如何您都必须更新字段的子集。

【讨论】:

  • 我测试了这个线程中提出的所有解决方案,并得出一个结论,处理这个问题的最佳方法确实是创建我自己的简单映射器,我提取了所有这些样板错误,以便它不会不必在其他任何地方重复。谢谢大家的建议。如果我说我今天没有被 Java 失望,那我就是在撒谎。对我来说,感觉像这样的东西早就应该是内置功能了。
【解决方案2】:

使用传统方式,比较罗嗦,但我们可以放心复制属性。

public Student copyFrom(Student student)
public void copyFrom(Student student)

其他方式,使用反射来复制值... 但是我们有时会遇到一些奇怪的问题……对于复杂的对象,例如 Map/List 和其他结构。 使用时请谨慎... 这是我在项目中使用的当前签名。

public void copyFrom(Object src, List<String> excludes) {
    final List<String> excFields = excludes;
    ReflectionUtils.doWithFields(src.getClass(), fieldCallback-> {});
    ....
  }

这里有一些与反射有关的基本方法。我用的是spring内置的ReflectionUtils,你可以自己写一个或者使用其他库...

Field field= ReflectionUtils.findField(cls, fieldName);
Method m = ReflectionUtils.findMethod(cls, fieldName);
field.set(this,value)

【讨论】:

    猜你喜欢
    • 2010-10-30
    • 2010-11-16
    • 1970-01-01
    • 2022-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-10
    相关资源
    最近更新 更多