数据传输对象中的公共字段

Lil*_*hal 26 java coding-style

在我多年的编程中,我经常创建一些类,只需将一些变量与setter和getter组合在一起.我已经看到这些类型的对象被称为值对象,域对象或模型对象,具体取决于它们使用它们的上下文.通用用法的最合适术语似乎是数据传输对象(DTO).这描述了仅包含访问器和增变器的POJO.

我刚刚编写了一个这样的对象,其中包含用于在图表上设置主题参数的大约50个字段.现在我想知道如果不是生成一百个getter和setter,我应该将这些字段声明为public.这样做违背了我编程本能告诉我的一切,但我不能否认它会大大增加我的代码的易读性并减少类中的样板代码量.

我可以看到使用公共字段的唯一原因是我需要对这些字段执行任何类型的验证.如果我们假设类型验证足以满足我的目的,那么在这种情况下使用公共字段是否可以接受面向对象设计?公共DTO在大批量操作中表现更好吗?

Joe*_*ckx 29

大多数程序员默认使用getter/setter私有字段而不考虑它.但就像任何货物崇拜的东西一样,最好做出有意识的决定.

使用getter/setter组合而不是公共字段的主要原因是您可以更改定义.因此,如果您的DTO是组件之间接口的一部分,那么最好使用getter.如果更改内部工作,则可以调整getter以模仿旧行为并保持兼容性.

另一个原因是您可以创建只读字段.通常对于DTO来说,只读和不可变是一个不错的选择.

第三个原因可能是你的DTO需要是一个javabean,因为你打算在一些需要它的工具中使用它.

如果这些属性都不适合您,则没有理由不使用公共字段.

不要期望有很大的性能差异:)

  • 另外一个用于不可移植性.如果可以使用Builder模式,还要考虑而不是使用setter.然后,您的大部分访问都将通过getter,允许您返回不可变项或安全副本,而这些项目您不希望通过副作用间接影响. (2认同)

adi*_*ath 8

数据结构和对象之间存在差异。

数据结构应该暴露其内部结构而不是行为。

一个对象不应该暴露它的内部结构,但应该暴露它的行为,这也被称为得墨忒耳法则

所以,DTO 基本上是数据结构。他们应该只暴露他们的数据,他们不需要 Getter 和 Setter。验证是行为,它不应该是 DTO 的一部分。它必须有一个不同的对象,即验证对象。

受到Robert C. Martin(鲍勃叔叔)的《干净代码》的启发


Wil*_*ill 5

我认为拥有一个具有公共属性的“设置”,“主题”或“样式”类并不是非常糟糕的做法。

如果您想在设置时进行任何复杂的计算或检查值,具有重构工具的现代IDE使得将属性提升为getter / setter变得很简单。

通常,在您的“ setTheme”或使用这些设置类的任何函数中,都是进行验证的好地方。

当设置这样的设置时,通常适合做一个深复制的对象,而不是保留对可变类的引用。


Wil*_*lsh 5

数据结构是一个公开数据的类,没有任何业务逻辑,例如:

class Name {
   public String firstName;
   public String lastName;
}
Run Code Online (Sandbox Code Playgroud)

这个数据结构:

  • 没有任何 getter/setter。
  • 不是一成不变的。

不可变的数据结构:

  • 也是一个公开数据的类。
  • 有一个全参数构造函数。
  • 具有所有最终字段。
  • 通过 getter 公开其数据。
  • 没有设置器。

例如:

class Name {
    private final String firstName;
    private final String lastName;

    public Name(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return this.firstName;
    }

    public String getLastName() {
        return this.lastName;
    }   
}
Run Code Online (Sandbox Code Playgroud)

数据传输对象:

  • 用于传输数据。
  • 是一种保存服务器往返的模式。
  • 包含序列化/反序列化信息。此信息通常取自 javax.validation 库。
  • 通常由 2 个不同的对象组成。
  • 不包含任何业务逻辑。

例如:

import javax.validation.Valid;

class UserDto {

    @Valid
    Name userName;
    @Valid
    Address userAddress;

    public UserDto(Name userName, Address userAddress) {
        this.userName = userName;
        this.userAddress = userAddress;
    }   
}
Run Code Online (Sandbox Code Playgroud)

现在我已经澄清了数据结构、不可变数据结构和 DTO 中的每个术语,我可以进行总结了。

DTO 用于传输数据。
数据在传输过程中不应被更改。
所以 DTO 应该是不可变的。例如

import javax.validation.Valid;

class UserDto {

    @Valid
    private final Name userName;
    @Valid
    private final Address userAddress;

    public UserDto(Name userName, Address userAddress) {
        this.userName = userName;
        this.userAddress = userAddress;
    }

    public Name getUserName() {
        return this.userName;
    }

    public Address getUserAddress() {
        return this.userAddress;
    }
}
Run Code Online (Sandbox Code Playgroud)

只需注意一下非基元,例如 Integer、String、Boolean 等,这些都是不可变的类。
一旦它们被构建出来,它们就不能被突变。
因此,如果将这些字段设为 Final,它们的引用将无法更新为指向不同的对象,并且它们的值也无法使用 Java API 进行更改。