【发布时间】:2023-04-01 21:09:01
【问题描述】:
我注意到在 Java(包括 C#)的许多地方,许多“getter”方法都以“get”为前缀,而许多其他方法则没有。我从未注意到 Sun 似乎遵循的任何模式。在 getter 方法名称中使用“get”有哪些准则或规则?
【问题讨论】:
-
在C#中,你应该更好地使用属性,它封装了get和/或set,让用户感觉就像在使用一个字段。
我注意到在 Java(包括 C#)的许多地方,许多“getter”方法都以“get”为前缀,而许多其他方法则没有。我从未注意到 Sun 似乎遵循的任何模式。在 getter 方法名称中使用“get”有哪些准则或规则?
【问题讨论】:
归结为语义。是的,C# 具有“属性”,它为您提供了一个 get/set 'method' 存根......但是 .NET Framework 中以“Get”开头的函数(......“方法”......)应该提示开发人员意识到某些操作的发生只是为了获得某些结果。
您可能认为这很奇怪,并说“为什么不直接使用返回类型来提示人们呢?”,答案很简单。考虑以下方法:
public Person CreatePerson(string firstName, string lastName) {...}
仅通过该方法的名称,您可能会想到其中涉及数据库活动,然后将返回一个新创建的“人”。
但是,这个呢:
public Person GetPerson(string firstName, string lastName) {...}
仅通过那个方法的名称,您就可以假设正在从数据库中100%“安全”地检索一个人。
您永远不会多次调用“CreatePerson”...但是您应该始终感到安全地调用“GetPerson”。 (它不应影响应用程序的“状态”)。
【讨论】:
public Person Person(string firstname) {...} 的东西——读起来不太好(如果它甚至可以编译?还没有使用C#)。在我见过的任何其他编程语言(public Person person(string firstname) {...})中或多或少地使用小写函数名称会带来很多混乱,也意味着不再需要get-前缀......所以你的论证是 C# 特有的。
public Person Person { get; set; } 要记住的另一件事是,c# 具有属性作为特性,而 java 没有(您使用方法,对吗?)。因此,语言在这方面是完全不同的。
我个人喜欢以下规则:
set 方法直接修改,请使用get 前缀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 的标签库),您将使用 user.name 访问 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# 中,这几乎是无关紧要的,因为无论如何都有“真正的”属性 :)
【讨论】:
get。鉴于上下文是 Java,与名称以“get”开头的函数相比,我不确定您所说的只读属性是什么意思...
这取决于。它通常是冗余信息,即使在没有属性的语言中也是如此。
在 C++ 中,通常提供 Attr() 函数的两个重载,而不是 getAttr()/setAttr() 对: 无效属性(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 命名约定*是一个有点不幸的故事,”他继续说道。 “对于通用开发来说,这是一个糟糕的惯例。这是在可视化编辑器中命名可视化组件的一个相当有针对性的约定,您可以在其中将按钮和标签以及类似的东西拖放到画布上,并且您可以编辑关于前景色和字体以及什么的属性表有你,可以通过反思发现。”
Goetz 解释说,命名约定是构建这些 UI 组件的好方法——事实证明,这并不是一个关键的 Java 用例。 “然而,不知何故,我们继续使用该命名约定,尽管它与大多数业务领域对象的匹配度很差。”
——https://blogs.oracle.com/javamagazine/java-architects-loom-panama-valhalla#anchor_4
* - 基本上是getX/setX 约定问题
【讨论】: