我先来说getter和setter的好处,再来说它们存在的历史原因。

和直接访问属性相比,我们可以在getter和setter实现不同的控制权限(modifier),比如说private的setter和public getter。我们还可以在getter和setter里实现额外的逻辑,比如说:

public void setCounter(int c) {
if (c < 0) {
throw new IllegalArgumentException();
}
this.counter = c;
}

这样做还有一个好处就是外部调用者是和getter和setter方法耦合,我们将来可以把这个类变成interface,你可能加入不同的实现类,比如说DBCounter, MemoryCounter,只要仍然向外暴露同样的getter和setter,调用方就无需改变。

但现在getter和setter泛滥并不是因为这些好处,而是非常多的框架spring,struts,hibernate等依赖这种模式。

因为这个模式其实有个历史原因,就是javabean,这是从jsp/servlet时代就开始有的概念,后来被非常多的Java 框架继承。在很多框架中以pojo的形式出现, 它就是一堆属性加上getter和setter再带一个无参数的constructor,它被很多很多老框架广泛采用,用于在不同层面传递数据,

但这个真的不是一个好设计,如果是来做model,你把所有私有属性都暴露出来,这明显是破坏了封装。如果仅仅是在不同层面传递数据,那我觉得不可更改的对象似乎更适合。有setter的对象很容易产生问题,有些值不对的时候,你都不知道在哪改的,也不好debug。

另外在并发情况下,我比较推荐使用immutable(内部状态无法再修改的)的对象,用一个constructor来初始化所有field, 然后只提供getters。这样至少能保证每一个bean初始化出来都是完整的。传统javabean你初始化需要调用一大组setter, 万一中间出现异常,你这个bean很可能处在一种不可预计的状态中,是很危险的。有朋友说,有的框架一定要依赖setter来赋值,的确有这种情况,那我想不出什么更好的办法,似乎这种情况下setter不能避免。但即便有setter,你自己的代码里也可以不调用setter. 因为mutable的坏处聊起来没底的。