我已经阅读了讨论"Why use getters and setters?"的stackoverflow页面,我已经确信使用setter的一些原因,例如:稍后验证,数据封装等。但是什么原因是什么无论如何都要使用getter?在获得字段值之前,我没有看到获取私有字段值或获得验证的原因造成的任何损害。 是否可以永远使用getter并始终使用点符号获取字段值?
答案 0 :(得分:4)
如果Java类中的给定字段对于读取(在表达式的RHS上)可见,则还必须能够分配该字段(在表达式的LHS)。例如:
class A {
int someValue;
}
A a = new A();
int value = a.someValue; // if you can do this (potentially harmless)
a.someValue = 10; // then you can also do this (bad)
除了上述问题之外,在类中使用getter的一个主要原因是为了保护该类的使用者免受实现细节的影响。 getter不一定只需返回一个值。它可以返回从Collection或其他东西中提取的值。通过使用getter(和setter),我们可以让类的使用者不必担心实现随时间的变化。
答案 1 :(得分:2)
我希望专注于实用性,因为我认为你已经在实际的实践中看到了概念上的好处。
明显的概念上的好处是可以在不影响使用这些功能的外部世界的情况下更改setter和getter。另一个特定于Java的好处是,所有未标记为final
的方法都能够被覆盖,因此您可以让子类将行为覆盖为奖励。
然而,您可能已经在以前听过这些概念上的好处,但对于您的日常场景来说,它仍然听起来有点过分。理解软件工程实践的一个难点是,它们通常用于处理由开发团队管理的非常真实的大型代码库。当你只是在自己的小项目上工作时,很多事情看起来都有点过分。
让我们进入一些实际的现实场景。我以前在一个非常大规模的代码库中工作。它是一个低级别的C代码库,具有很长的遗产,有时几乎不会超过汇编,但我在那里学到的许多课程都转化为各种语言。
在这个代码库中,我们遇到了很多错误,其中大部分都与状态管理和副作用有关。例如,我们遇到过一个结构的两个字段应该保持彼此同步的情况。一个字段的有效值范围取决于另一个字段的值。然而,我们遇到了这两个字段不同步的错误。不幸的是,因为它们只是具有全局范围的公共变量(' global'应该被认为是可以访问变量而不是绝对的代码量的程度 ),可能有数万行代码可能是罪魁祸首。
作为一个更简单的例子,我们遇到了一个字段的值永远不应该是负面的情况,但在我们的调试会话中,我们发现了负值。让我们称这个值永远不应该为负,x
。当我们发现x
导致的错误为负数时,x
被任何事物触及的时间很长。所以我们花了好几个小时放置内存断点并试图通过查看以某种方式修改x
的所有可能位置来在大海捞针中找到针。最终我们发现并修复了这个错误,但这是一个应该在几年前被发现的错误,应该不那么痛苦。
如果代码库的大部分内容不是直接访问x
而是使用set_x
之类的函数,那么就会出现这种情况。如果是这种情况,我们可以做一些简单的事情:
void set_x(int new_value)
{
assert(new_value >= 0);
x = new_value;
}
......我们会立即发现罪魁祸首并在几分钟内解决它。相反,我们在臭虫被引入多年后就发现了它,它花了我们一丝不苟的时间来追查并修复它。
这是我们为忽视工程智慧而付出的代价,并且在处理了第10,000个问题之后,这个问题可以通过简单的操作来避免,例如依赖于函数而不是整个代码库中的原始数据,如果你的头发避风港&#那时候所有人都变成了灰色,你通常不会有愉快的性格。
吸气剂和二传手的最大价值来自于二传手。您通常希望控制最多的状态操作以防止/检测错误。由于需要setter修改数据,因此getter成为必需品。然而,当你想要非侵入式地交换一个原始状态进行计算时(通过改变一个函数的实现),getter也很有用,例如
您职业生涯早期最难欣赏的事情之一就是界面稳定性(防止公共界面不断变化)。只有通过规模项目和可能与第三方的兼容性问题才能理解这一点。
当您自己处理一个小项目时,您可以将一个类的公共定义更改为您心中的内容,并使用它重写所有代码以使用您的内容更新它变化。由于使用界面的代码量可能很小(例如:使用您的类的几百行代码,以及您个人使用的所有代码),以这种方式不断重写代码似乎不是一件大事。写)。
当您处理大型项目并查看数百万行代码时,更改广泛使用的类的公共定义可能意味着需要使用该类重写100,000行代码作为响应。而且很多代码甚至不会成为您自己的代码,因此您必须深入分析和修复其他人的代码,并可能与他们密切协作以协调这些更改。其中一些人甚至可能不在您的团队中:他们可能是为您的软件编写插件的第三方或已转移到其他项目的前开发人员。
你真的不想反复遇到这种情况,所以设计公共界面以保持稳定(不变)成为你最中心界面的关键技能。如果这些接口泄漏了原始数据等实现细节,那么一次又一次地改变它们的诱惑将成为您可以一直面对的场景。
因此,您通常希望设计界面以专注于"什么"他们应该这样做,而不是"如何"他们应该这样做,因为"怎么"可能比#34;什么"更频繁地改变。例如,函数可能应该将新元素追加到列表中。但是,您可能希望将其使用的列表数据结构替换为另一个,或者引入锁定以使该功能线程安全("如何"关注)。如果这些"如何"关注点不会泄漏到公共接口,然后您可以在本地更改该类的实现(它是如何处理的),而不会影响请求它执行任何操作的任何现有代码。
你也不希望课程做得太多而变得单一,因为那时你的班级变量将变得更加全球化。 (即使在课堂实施中也能看到更多的代码),当它已经做了这么多时,它也很难适应稳定的设计(课程越多,他们想要做的更多。)
吸气剂和制定者不是这种界面设计的最佳例子,但他们确实避免暴露那些"如何"细节至少略好于公开暴露的变量,因此更改(休息)的理由较少。
是否可以永远使用getter并始终使用点表示法获取字段值?
这有时候可以。例如,如果您正在实现树结构并且它使用节点类作为客户端从不直接使用的私有实现细节,那么过于努力地专注于此节点类的工程可能会开始变得适得其反。
您的节点类不是公共接口。它是您树的私有实现细节。您可以保证它不会被树实现以外的任何东西使用,因此应用这些实践可能会有点过分。
您不想忽略此类做法的地方在真正的公共接口(树界面)中。您不希望允许树被滥用并处于无效状态,并且您不想要一个不稳定的界面,在树被广泛使用后您经常想要改变很久
另一种情况可能是好的,如果您只是在处理废料项目/实验作为一种学习练习,并且您确定您编写的代码是相当一次性的,并且永远不会用于任何规模的项目或成长为任何规模。
尽管如此,如果您对这些概念不熟悉,我认为即使您的小规模项目在使用getter / setter方面犯错也是一项有用的练习。这与Miyagi先生如何让Daniel-San画出围栏,洗车等等相似.Daniel-San发现这一切毫无意义,他的手臂已经筋疲力尽了。然后Miyagi先生去了hyah hyah hyoh hyah" Daniel-San使用间接训练来阻止所有人,但却没有意识到他是如何做到这一点的。
答案 2 :(得分:0)
在java中,您无法告诉编译器允许从外部对公共字段进行只读访问。
因此暴露公共领域为无法修改打开了大门。
答案 3 :(得分:0)
字段不是多态的。
吸气剂的替代品将是公共领域;但是,字段不是多态。
这意味着您无法扩展课程并且"覆盖"这个领域没有引入奇怪的行为。基本上,您获得的价值取决于您如何参考该领域。
此外,您不能在界面中包含该字段,并且您无法执行验证(这更适用于设置者)。