使用getter和setter(只获取和设置)而不是简单地为这些变量使用公共字段有什么好处?

如果getter和setter所做的不仅仅是简单的get/set,我可以很快地解决这个问题,但我不是100%清楚如何做到:

public String foo;

比:

private String foo;
public void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return foo; }

而前者需要的样板代码要少得多。


当前回答

事实上,考虑使用访问器而不是直接公开类的字段有很多很好的理由——不仅仅是封装和使未来的更改更容易。

以下是我知道的一些原因:

与获取或设置属性相关的行为的封装-这允许以后更容易地添加附加功能(如验证)。隐藏属性的内部表示形式,同时使用替代表示形式公开属性。隔离您的公共接口不受更改的影响——允许公共接口在实现更改时保持不变,而不影响现有用户。控制属性的生存期和内存管理(处置)语义——在非托管内存环境(如C++或Objective-C)中尤为重要。在运行时为属性更改时提供调试拦截点-在某些语言中,如果没有此功能,则很难调试属性更改为特定值的时间和位置。改进了与旨在针对属性getter/setter进行操作的库的互操作性——Mocking、Serialization和WPF应运而生。允许继承者通过重写getter/setter方法来更改属性的行为和公开方式的语义。允许getter/setter作为lambda表达式而不是值传递。获取器和设置器可以允许不同的访问级别-例如,获取可以是公共的,但集合可以受到保护。

其他回答

很多人都在谈论二传手和二传手的优点,但我想扮演魔鬼代言人的角色。现在我正在调试一个非常大的程序,程序员们决定让所有的东西都变得更好和更好。这看起来不错,但这是一场逆向工程噩梦。

假设你正在查看数百行代码,你会发现:

person.name = "Joe";

这是一段非常简单的代码,直到你意识到它是一个setter。现在,您遵循该setter,发现它还设置了person.firstName、person.lastName、person.isHuman、person.hasReallyCommonFirstName,并调用person.update(),后者将查询发送到数据库等。哦,这就是发生内存泄漏的地方。

乍一看就理解一段本地代码是具有良好可读性的一个重要特性,getter和setter往往会打破这一特性。这就是为什么我尽量避免使用它们,并在使用它们时尽量减少它们所做的事情。

原因有很多。我最喜欢的是当你需要改变行为或调整你可以设置的变量时。例如,假设您有一个setSpeed(intspeed)方法。但你希望你只能将最大速度设置为100。您可以执行以下操作:

public void setSpeed(int speed) {
  if ( speed > 100 ) {
    this.speed = 100;
  } else {
    this.speed = speed;
  }
}

现在,如果代码中的每个地方都使用公共字段,然后意识到需要上述要求,该怎么办?寻找公共领域的每一种用法,而不仅仅是修改你的setter。

我的2美分:)

getter/setter的一个相对现代的优点是,它使在标记(索引)代码编辑器中浏览代码变得更容易。例如,如果您想查看谁设置了成员,可以打开setter的调用层次结构。

另一方面,如果成员是公共的,则这些工具无法过滤对该成员的读/写访问。因此,您必须费力地使用该成员。

在不支持“财产”(C++、Java)或在将字段更改为财产(C#)时需要重新编译客户端的语言中,使用get/set方法更容易修改。例如,向setFoo方法添加验证逻辑不需要更改类的公共接口。

在支持“真实”财产的语言中(Python、Ruby或Smalltalk?),没有必要使用get/set方法。

除非您当前的交付需要,否则不要使用getters setter。例如,如果要更改任何内容,请不要过多考虑将来会发生什么,这是大多数生产应用程序和系统中的更改请求。

思考简单、简单,必要时增加复杂性。

我不会仅仅因为我认为这是正确的或者我喜欢这种方法,就利用对拥有深厚技术知识的企业主的无知。

我编写了一个没有getters setter的大型系统,只使用了访问修饰符和一些验证n perform-biz逻辑的方法。如果您确实需要。使用任何东西。