我注意到在 Java(包括 C#)的许多地方,许多“getter”方法都以“get”为前缀,而许多其他方法则没有。我从未注意到 Sun 似乎遵循的任何模式。在 getter 方法名称中使用“get”的一些准则或规则是什么?
10 回答
它归结为语义。是的,C# 具有“属性”,它为您提供了一个 get/set 'method' 存根......但是 .NET Framework 中以“Get”开头的函数(......“方法”......)应该是线索开发人员意识到某些操作仅出于获得某些结果的目的而发生。
你可能会觉得这很奇怪,然后说“为什么不直接使用返回类型来提示人们呢?”,答案很简单。考虑以下方法:
public Person CreatePerson(string firstName, string lastName) {...}
仅通过该方法的名称,您可能会想到将涉及数据库活动,然后将返回一个新创建的“人”。
但是,这个呢:
public Person GetPerson(string firstName, string lastName) {...}
仅凭该方法的名称,您就可以假设正在从数据库中 100% “安全”地检索人员。
您永远不会多次调用“CreatePerson”......但您应该始终安全地调用“GetPerson”。(它不应该影响应用程序的“状态”)。
我个人喜欢以下规则:
get
只要值可以通过相应的set
方法直接修改,就使用前缀get
在值无法直接设置为属性的情况下删除前缀(即没有等效的 setXXX 方法)
第二种情况的基本原理是,如果该值不是真正的用户可设置的“属性”,那么它不应该需要一对 get/set 方法。一个暗示是,如果遵循此约定并且您看到 getXXX 方法,那么您也可以假设存在 setXXX 方法。
例子:
String.length()
- 由于字符串是不可变的,因此长度是只读值ArrayList.size()
- 添加或删除元素时大小会发生变化,但不能直接设置
Java中的“get”和“set”前缀对最初用作表示java bean的约定。后来,它变成了一种封装约定,因为 Java 与 C# 不同,没有适当的属性。
Java中的最佳实践是对属性使用 get 和 set 前缀。
框架、标签库等将寻找带有这些前缀的方法并将它们用作属性。
所以,如果你有一个像这样的java类......
public class User{
private String name;
public String getName(){ return name;}
public void setName(String name){ this.name = name; }
}
.. 使用 struts-tags(或任何其他基于 ognl 的标签库),您将使用 .name 访问 name 属性user.name
。
Spring 框架也在 xml 配置文件中使用此约定。
Java(还)不支持属性。Getter 和 setter 是解决这个问题的障碍。其他语言 - 包括 C# - 支持属性,您应该使用这些来代替。这也不仅仅是一个“最佳实践”:C# 中的序列化将依赖于属性,而不是 getter 和 setter,因此如果您需要序列化类,将来不使用属性可能会导致各种问题。
属性的优点是它们使代码更具可读性。就像是
obj.setX(10);
在 Java 中,变成
obj.X = 10;
然而在幕后,X 是一种方法,而不是一个变量,因此可以执行脏输入检查等。
过去,API 经常暴露只读属性而不带get
前缀:当然是这样的String.length()
,甚至更新Buffer.capacity()
的也是合理的例子。
这样做的好处是涉及的绒毛较少。缺点是任何试图根据约定自动确定属性的东西都不会发现它们。就我个人而言,我倾向于在包含前缀方面犯错。
当然,在 C# 中,这几乎是无关紧要的,因为无论如何都有“真实”的属性 :)
这取决于。它通常是冗余信息,即使在没有属性的语言中也是如此。
在 C++ 中,通常提供 Attr() 函数的两个重载,而不是 getAttr()/setAttr() 对: void Attr(Foo f); // 设置器 Foo Attr(); // 吸气剂
在 Java 中,通常的做法是为 get/set 添加前缀。我不得不说最好的做法是使用你的语言的标准。在 Java 中,人们希望看到 get/set 前缀,因此省略它们可能会使人们感到困惑,即使它们并不是绝对必要的。
只是一个简短的附录:另一个约定是布尔字段的 getter 以“is”而不是“get”为前缀,例如bool isEnabled() { return enabled; }
Objective C 2.0 也使用属性,使用相同的点语法。
在此之前,它对 getter 和 setter 使用了稍微不同的命名方案(当然,它仍然可以与属性一起使用,或者用于普通的旧属性)。
value = [obj attr];
[obj setAttr:value];
[obj getAttr:&value];
也就是说,get 以不同的方式使用。它不返回值,而是将结果存储在传入的变量中。
典型的 getter 与属性同名,setter 是以 set 为前缀的属性(根据 Java 的约定)。KVO(Key-Value Observation)系统使用这些约定,因此应遵守。
13 年后,我相信这个问题值得重新审视。当然,随着时间的推移,有很多 stackoverflow 问答(甚至这里有一些很好的答案)、文章和博客文章都得出了相同的结论,但我认为,最后,我们从 Brian Goetz 本人那里得到了一个相当直截了当的答案:
“JavaBeans 命名约定* 有点不幸,”他继续说道。“对于通用开发来说,这是一个糟糕的惯例。这是在可视化编辑器中命名可视化组件的一个相当有针对性的约定,您可以在其中将按钮和标签以及类似的东西拖放到画布上,并且您可以编辑关于前景色和字体以及什么的属性表有你,可以通过反思发现。”</p>
Goetz 解释说,命名约定是构建这些 UI 组件的好方法——事实证明,这并不是一个关键的 Java 用例。“然而,不知何故,我们继续使用该命名约定,尽管它与大多数业务域对象的匹配度很差。”</p>
– https://blogs.oracle.com/javamagazine/java-architects-loom-panama-valhalla#anchor_4
*
– 基本上,有问题的getX
/setX
约定