原文作者: Shamik Mitra
原文链接:https://dzone.com/articles/why-should-i-write-getters-and-setters
当我开始我的java职业生涯的时候,我就对getters 和setters感到疑惑。有一个问题经常在我脑海里冒出来:为什我要写getters和seters。这种语法对我来说是很奇怪的。
我知道如果用public来修饰的话,类中的变量可以被所有包(packages)访问到,getters/setters 方法也是这样。我也在做相同的事情——用private修饰变量,同时用public修饰其对应的getters 和setters方法,这样就可以在所有包中访问了。
所以下面两种写法有什么不同呢?
public String name = "Shamik";
// caller:
String name = X.name; //(X is a object instance);
X.name = "Shamik Mitra";
private String name = "Shamik";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// caller:
String name = X.getname();
X.setName("Shamik Mitra");
后来我慢慢意识到为什我们要使用getters/setters,还有为何他们如此重要。在这篇文章中,我会分享一些相关的感悟。
感悟
“用public修饰一个变量”和“通过getters/setters来操作这个变量”最主要的区别是在实质上保持变量的控制。如果你用public修饰一个变量,这以为着你可以直接访问到它,并且可以对这个变量做所有操作。例如,你可以把这个变量设为null,当你在其他方法中使用这个变量的时候,可能抛出空指针异常。
但是,如果你提供了getter/setter方法,这是一种间接的访问,它并不能完全地控制这个变量。为这个变量赋值的唯一方法就是通过setter方法,同样地只能通过getter方法来获取变量的值。所以现在你所定义的变量就只有一个“入口”和“出口”。并且,因为getter/setter是方法,这意味着里面可以写代码,你可以做校验去检查这些变量。因此,对象可以决定是否为这个变量赋值。当调用getter方法的时候,你可以决定返回一个真正的引用或者是复制它并返回。
所以 getters/setters 就像是保险丝或者是断路器。当发生什么错误的时候,保险丝就会从主电路中分离以保证电路是安全的。这里概念是一样的,如果有什么错误发生,setter可以不把值传过去。
当你看完这些解析之后,我知道你仍然有一个问题:
“你说的我知道啊,但通常,我们都不在getters/setters方法里面写其他东西。我们只是返回和设这个变量。这和直接用pulic修饰变量,把它完全暴露出去一样。所以你说这些做什么?”
对于这个问题,我说的是在写getters/setters的时候,我们创建了一个规制可以在以后加入任何的校验。现在里面是没有校验,但以后有什么问题的话,我们只需要在setter里面加入校验相关的代码就行了。
但对于这个问题现在仍然有很多争论,并且有很多人支持下面这个观点:YAGNI (You Ain't Gonna Need It——你根本就不需要它)。他们说,当这个变量没有必要去校验的时候,为什么还要这么麻烦去写getter/setter?我直接用public 把它公开得了。
按我的理解,YAGNI的主要问题是想要使代码避免不必要的复杂。这就像有些人会想得很多,他们使代码尽量地简单普通以便之后做任何修改。但大多数他们所考虑到的改变都不会来。
总结
getters/setters 不会使你的代码变得复制,并且是便于以后的校验。所以,尽管写吧。
译者注: getters/setters的概念出现已经很久了,对于有经验的程序员或许都有自己的理解。其实我们现在写getters/setters方法很多时候是受到框架的约束,无论是在数据端和前端都大量使用到javaBean,getters/setters是必不可少的。写起来也不麻烦,反正编译器可以直接生成。 但现在有写数据存储的框架已经开始舍弃getter和setter,甚至连成员变量也舍弃了,直接用一个map来保持变量名和其对应的值, 使代码变得非常的简洁。当然,这也有着明显的缺点。