使用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往往会打破这一特性。这就是为什么我尽量避免使用它们,并在使用它们时尽量减少它们所做的事情。

我只想抛出注释的概念:@getter和@settier。使用@getter,您应该能够obj=class.field,但不能使用class.field=obj。使用@settier,反之亦然。使用@getter和@setter,您应该能够同时做到这两个。这将通过在运行时不调用平凡的方法来保持封装并减少时间。

虽然getter和setter不常用,但这些方法的使用也可以用于AOP/代理模式的使用。例如,对于审计变量,您可以使用AOP来审计任何值的更新。没有getter/setter,除了到处更改代码外,其他都是不可能的。我个人从未使用过AOP,但它显示了使用getter/setter的另一个优势。

我能想到一个原因,为什么你不希望一切都公开。

例如,您从未打算在类外部使用的变量可以被访问,甚至可以通过链变量访问(即object.item.origin.x)直接访问。

通过将所有内容都设为私有,并且仅将您想要扩展的内容以及可能在子类中引用的内容设为受保护的,并且通常只将静态最终对象设为公共,那么您就可以通过使用setter和getter访问您想要的程序内容来控制其他程序员和程序可以在API中使用什么,以及它可以访问什么,以及不能访问什么,或者可能是其他恰好使用您的代码的程序员,可以在您的程序中进行修改。

代码不断演变。private非常适合需要数据成员保护的情况。最终,所有的类都应该是一种“小程序”,它有一个定义良好的接口,你不能只使用它的内部结构。

也就是说,软件开发并不是要设置课程的最终版本,就好像你在第一次尝试时按下了一些铸铁雕像一样。当你使用它时,代码更像粘土。它随着你的发展而发展,并进一步了解你正在解决的问题领域。在开发过程中,类之间可能会发生不应有的交互(您计划排除的依赖关系)、合并或拆分。因此,我认为争论归结为人们不想虔诚地写作

int getVar() const { return var ; }

所以你有:

doSomething( obj->getVar() ) ;

而不是

doSomething( obj->var ) ;

getVar()不仅在视觉上很嘈杂,而且给人一种错觉,认为getingVar(()在某种程度上是一个比实际更复杂的过程。如果你的类有一个passthrough setter,那么你(作为类编写者)如何看待var的神圣性对你的类的用户来说尤其令人困惑——那么你似乎在设置这些门来“保护”你坚持认为有价值的东西,(var的神圣性)但即使你承认,任何人只要进来并将var设置为他们想要的任何值,而你甚至不去偷看他们在做什么,那么var的保护就没有多大价值。

所以我按如下方式编程(假设采用“敏捷”类型的方法——即当我编写代码时不知道它将要做什么/没有时间或经验来规划一个复杂的瀑布式界面集):

1) 从具有数据和行为的基本对象的所有公共成员开始。这就是为什么在我所有的C++“示例”代码中,你会注意到我到处使用结构而不是类。

2) 当对象对数据成员的内部行为变得足够复杂时(例如,它喜欢以某种顺序保存内部std::list),就会编写访问器类型函数。因为我是自己编程的,所以我并不总是立即将成员设置为私有,但是在类的进化过程中,成员将被“提升”为受保护或私有。

3) 完全充实并对其内部有严格规则的类(即,它们确切地知道自己在做什么,你不能“操”(技术术语)它的内部)被赋予类名称,默认为私有成员,只有少数成员被允许公开。

我发现这种方法可以让我避免在一个类进化的早期阶段,当大量数据成员被迁移、转移等时,坐在那里虔诚地编写getter/setter。