为什么我不应该使用不可变的POJO而不是JavaBeans?

2022-08-31 12:36:37

我现在已经实现了一些Java应用程序,到目前为止只有桌面应用程序。我更喜欢使用不可变对象在应用程序中传递数据,而不是使用具有赋值器(setters和getters)的对象,也称为JavaBeans。

但是在Java世界中,使用JavaBeans似乎更为常见,我不明白为什么我应该使用它们。就个人而言,如果代码只处理不可变对象,而不是一直改变状态,则代码看起来会更好。

第 15 项:最小化可变性有效的 Java 2ed 中也建议使用不可变对象。

如果我有一个对象实现为JavaBean,它看起来像这样:Person

public class Person {
    private String name;
    private Place birthPlace;

    public Person() {}

    public setName(String name) {
        this.name = name;
    }

    public setBirthPlace(Place birthPlace) {
        this.birthPlace = birthPlace;
    }

    public String getName() {
        return name;
    }

    public Place getBirthPlace() {
        return birthPlace;
    }
}

同样实现为不可变对象:Person

public class Person {
    private final String name;
    private final Place birthPlace;

    public Person(String name, Place birthPlace) {
        this.name = name;
        this.birthPlace = birthPlace;
    }

    public String getName() {
        return name;
    }

    public Place getBirthPlace() {
        return birthPlace;
    }
}

或者更接近 C 中的 a:struct

public class Person {
    public final String name;
    public final Place birthPlace;

    public Person(String name, Place birthPlace) {
        this.name = name;
        this.birthPlace = birthPlace;
    }
}

我还可以在不可变对象中使用 getter 来隐藏实现细节。但是由于我只使用它作为一个,我更喜欢跳过“getters”,并保持简单。struct

简单地说,我不明白为什么使用JavaBeans更好,或者我是否可以并且应该继续使用我不可变的POJO?

许多Java库似乎对JavaBeans有更好的支持,但随着时间的推移,对不可变POJO的更多支持可能会变得更加流行?


答案 1

  • 你必须与期望它们的环境进行交互
  • 您有很多属性,在实例化时进行所有初始化是不方便的
  • 您的状态昂贵或由于某种原因无法复制,但需要突变
  • 您认为在某些时候,您可能必须更改访问属性的方式(例如,从存储值移动到计算值,访问授权等)
  • 你想遵守编码标准,盲目地坚持认为使用JavaBeans在某种程度上更“面向对象”

在以下情况下首选不可变的 POJO:

  • 您有少量的简单属性
  • 您不必与假设JavaBean约定的环境进行交互
  • 克隆对象时很容易(或至少可能)复制状态
  • 你根本没有打算克隆对象
  • 您非常确定您永远不必修改如上所述访问属性的方式
  • 你不介意听抱怨(或嘲笑)你的代码如何不够“面向对象”

答案 2

令我惊讶的是,Thread这个词在这次讨论中没有出现。

不可变类的主要优点之一是,由于没有可变的共享状态,它们本质上更具线程安全性。

这不仅使您的编码更容易,而且还会给您带来两个性能优势作为副作用:

  • 减少对同步的需求。

  • 使用最终变量的更大范围,这可以促进后续的编译器优化。

我真的在尝试转向不可变对象,而不是JavaBean风格的类。通过 getter 和 setter 暴露对象的内脏可能不应该是默认的选择。