40

为什么 Java 方法名称如此广泛地使用“get”前缀?至少在我的 Java 程序中,有很多名称以“get”开头的方法。获取方法的百分比非常高。我开始觉得“得到”这个词由于通货膨胀而失去了意义。这是我的代码中的噪音。

我注意到在函数式/声明式编程和 PL/SQL 中使用了不同的命名约定。方法名称只是说明方法返回的内容。而不是account.getAmount()orTime.getIsoFormattedDateString(Date date)他们将使用account.amount()and Time.isoFormattedDateString(Date date)。这对我来说非常有意义,因为函数的名称描述了评估方法的结果(假设没有副作用,无论如何都不应该有)。“get”前缀似乎是多余的。

我刚刚开始阅读“清洁代码”一书。它说方法应该只做一件事,而那件事通常应该是以下之一:

  1. 通知某个对象有关事件,通常将事件作为参数传递。
  2. 询问有关某个对象的问题,通常使用形成自然语言语句的方法名称,将对象作为参数传递并返回布尔值。
  3. 获取一些东西,可能传递一些查找键或一些要转换的对象作为参数,并始终返回所需的对象/值。

我的问题是关于第三类的。这种方法除了“get”之外还有命名约定吗?您在选择方法名称/前缀时使用什么标准?

这是一个例子:

我有一个有两种方法getDates()getSpecialDates(). getDates()只返回私有变量的值(对日期集合的引用)。据我了解,这是一个标准的吸气剂。getSpecialDates()是不同的; 它调用getDates(),从另一个类中获取过滤器,应用过滤器并返回实际上是getDates().

方法 getSpecialDates() 可以命名为computeSpecialDates()findSpecialDates()selectSpecialDates()其他名称elicitSpecialDates()。或者我可以简单地命名它specialDates()。然后,为了保持一致,我可以重命名getDates()dates().

为什么要费心区分应该以“get”为前缀的方法和不应该以“get”为前缀的方法,为什么还要为“get”寻找替换词?

4

20 回答 20

27

I personally don't use getters and setters whenever it's possible (meaning : I don't use any framework who needs it, like Struts for instance).

I prefer writing immutable objects (public final fields) when possible, otherwise I just use public fields : less boiler plate code, more productivity, less side effects. The original justification for get/set is encapsulation (make your objects as shy as possible), but in fact, I don't need it very often.

In Effective Java, Joshua Bloch makes this compelling recommendation :

Classes should be immutable unless there's a very good reason to make them mutable... If a class cannot be made immutable, limit its mutability as much as possible.

In the same book, he also says (but I don't want to copy the whole book here) :

The JavaBeans pattern has serious disadvantages.

I totally aggre with that, since JavaBeans were originally intended for a very narrow problem domain : manipulation of graphical components in an IDE. It is a bad practice to use one solution designed for solving another problem.

于 2010-07-09T10:55:34.823 回答
16

它来自JavaBeans 命名约定

于 2010-07-09T09:02:26.840 回答
9

有这么多 get* 方法的部分原因是 Java 不支持 .net/COM 等“属性”,Java bean 和此类使用函数 getX 和 setX 来复制名为 X 的属性的功能。 Java 利用这一点来允许设置和检索属性。

于 2010-07-09T08:58:41.060 回答
6

getSpecialDates()像, computeSpecialDates(),和findSpecialDates(),这样的方法名称对我来说是命令,因为它们的名称中使用了动词(动作)。每次调用命令时,命令都会产生副作用。而像, , [nouns] 这样的方法名称是返回有用值且没有副作用的方法。多次调用该方法每次都返回相同的值,除非调用了一个副作用是改变状态的命令。selectSpecialDates()elicitSpecialDates()date()dates()specialDates()

于 2010-07-12T02:02:47.497 回答
6

getter 和 setter 方法经常用 Java 编写的原因之一是因为使用了JavaBeans约定。

然而,标准 Java API 在这方面本身并不一致。例如,类String有一个length()方法,而接口Collection定义了一个size()方法,而不是getLength()or getSize()

Java 不支持统一访问原则,所以你必须编写 getter 和 setter 方法来访问属性。

于 2010-07-09T09:05:53.340 回答
5

一个原因是它是Java Bean Spec的重要组成部分。

于 2010-07-09T09:01:26.997 回答
4

要求 Java 开发人员使用通用 get/set 约定的原因之一是许多框架依赖它来创建 bean 和设置字段。例如,如果您为 Spring bean 配置了一些属性,并且类中<property name="foo" value="bar" />没有命名方法setFoo(),那么在创建 bean 时会出错。

于 2010-07-09T09:07:34.100 回答
4

前提1:一个方法应该只做一件事。前提 2:getter 方法——不管它是否使用 get 前缀——应该没有副作用。鉴于这两个前提,我建议: 一种方法,其作用是获取某些东西,并且以相对简单且廉价的方式这样做,其名称中不需要有动词。

getter 的存在理由不是做某事,而是评估某事。我们对该方法的作用不感兴趣。由于它没有副作用,因此该方法中进行的任何计算都不会引起任何兴趣。我们只对方法返回的内容感兴趣。方法名称应以名词的形式反映。仅由名词组成的方法名称应始终为“getter”。

前缀“get”中的信息可以从缺少动词中推断出来。这比使用 get 前缀更简单、更直观。

可以假定名称仅由名词组成并具有返回值的方法没有副作用并且相对便宜。名称包含动词且没有返回值的方法存在具有副作用。可以假定名称包含动词并具有返回值的方法相对昂贵并且可能具有副作用。

似乎每个人都在到处写“get”的原因仅仅是源自 JavaBeans 模式的教条传统。当您实际计划使用需要它的工具/框架时,请保留 get 前缀!

于 2010-07-13T09:54:15.320 回答
3

正如许多人已经说过的,get..() 和 set()... 是 Java Beans Convention 的一部分。这对于与 Java 规范的其他部分进行互操作是必要的。例如,在 JSP 中,您可以通过指定不带get前缀的属性名称来访问 Java 中的成员。

鉴于豆: -

public class Foo {
  public int getX() { return 1; }
}

我们可以执行以下 JSP 来获取 X:-

<jsp:useBean id="aFoo" class="Foo" />
<c:out value="${aFoo.X}" />

这种方法除了“get”之外还有命名约定吗?

是的,您可以使用is而不是get布尔属性。

于 2010-07-09T09:58:23.923 回答
3

就个人而言,我沉迷于get. 这只是人类的语言。当你想要某事时,你就想要get某事。get前缀没有错。关于命名约定,我可以想到Select数据库查询的前缀——SelectUsers例如。

于 2010-07-09T08:58:03.487 回答
3

当我们生活在这样一个时代,任何值得拥有的 IDE 都会为您的私有变量生成 getter 和 setter 并让您在不想阅读它们时将它们折叠起来,那么“get”有什么意义呢?

你真正的问题应该是关于设计:为什么你的对象有这么多属性?如果您的对象只有 getter 和 setter,那么您是否患有“贫血的域模型”?

C#{get, set}表示法稍微好一点,因为它减少了代码行数,但你仍然需要为每个变量键入那个讨厌的“get”。

于 2010-07-09T11:24:53.880 回答
3

正如其他人所提到的,它适用于 Java Beans。但是,如果您使用的是 Java,请仅命名一个方法 getXXX(),前提是它只返回一个值并且不执行任何其他操作。就像您暗示的那样,如果它正在做其他事情,请将其命名为不同的名称,例如 computeXXX()。

我有时会发现有 50 行代码的 getXXX() 方法——如果是这种情况,那么你做错了。

于 2010-07-09T19:24:02.947 回答
2

我开始觉得“得到”这个词由于通货膨胀而失去了意义。这是我的代码中的噪音。

我稍微不同意这个结论。我不会说它失去了意义,我会说,由于它被广泛使用,带有 get 前缀的方法几乎可以完成您期望它们做的事情。

对于以下示例:

Time.isoFormattedDateString(Date date)

这是否根据输入参数设置格式类型,以便所有后续调用都使用此格式?

我知道有人会得出这个结论有点牵强,因为它是一个静态方法,但你确定是否在实例上调用了这个方法?可能,但使用 get 消除了所有歧义:

getIsoFormattedDateString(Date date)

在我看来,属性是一个比完全删除 get 更优雅的解决方案。

于 2010-07-09T09:52:01.513 回答
1

历史片段:如果您查看一些最早的 Java 1.0 API(JavaBeans 之前),您会发现它们没有“get”前缀。例如 java.awt.Container#minimumSize() 被#getMinimumSize() 取代。

于 2010-07-09T10:05:57.150 回答
1

我认为这是“给你的变量和函数起有意义的名字”理想的一个子集。

正如许多人所指出的,“get”在 Java Bean 中具有特定的含义。因此,我认为它应该仅限于用于检索内部变量的值,可能会产生副作用。我认为如果“获取”涉及较小的计算,例如进行数据类型转换或从嵌入式类中提取值或重新解释其他值,例如“public int getRightMargin() { return width-margin.left; }”,这是可以接受的。任何副作用都应仅限于获取值的真正“副作用”,例如设置一个表示已检索的标志。

但是如果有严重的计算,我认为它不应该被称为“get”。也许“计算”或其他。

如果我们在命名函数时使用一致的术语会很好,例如如果我们都同意“读取”意味着主要活动是从数据库中检索某些内容,而“计算”意味着进行计算或类似的事情。但这可能是不现实的:也许有太多的案例有细微的差别。

于 2010-07-09T15:22:46.487 回答
1

一种选择是保留get返回原始值或不可变值的方法的前缀,但删除返回可用于修改原始接收者的引用的方法的前缀。

例如 in java.util.Mapsize()可以调用getSize()keySet()不会调用getKeySet()

于 2010-07-13T10:30:18.893 回答
0

我仅将 get 和 set 用于仅获取或设置属性而不是其他方法的方法。

于 2010-07-09T09:01:58.353 回答
0

好吧,尽管 JavaBeans 规范要求您声明 getter 和 setter,但除非绝对必要(如许多 MVC 框架的情况),否则我通常不会声明它们。我在 Java 职业生涯中做了很多工作,我倾向于将变量声明为 public(是的,这听起来有点非 OOPy)。但我喜欢它,因为它看起来简洁而且“我”知道自己在做什么。它的唯一优点是减少了行数。

于 2010-07-09T09:05:22.777 回答
0

Java Beans 非常遵守它的命名约定,比如假设你声明了一个变量名 Name,对应的 setter 为 setName()。但它会产生一个错误,因为 setName 必须对应于 'name' 而不是 Name。另一个例子 boolean isReadey; 使用吸气剂 isReady()。再次出错,因为它正在寻找布尔就绪。因此,在编写代码之前,您必须熟悉此命名约定。但我个人更喜欢这种约定,因为它使程序员的工作变得容易,并且在你使用它片刻之后似乎有点合乎逻辑。

于 2010-07-09T09:26:00.880 回答
-1

保留“get”前缀很重要,因为:

  • 一个方法应该声明一个动作,因此它的名字中必须包含一个动词

  • get 表明变量的状态不会改变

  • 您将如何轻松地区分方法account()与此表达式中的变量account

    newAccount = currentAccount + account()--- 这是account()做什么的?


您在代码中看到太多 getter 的原因应该让您担心!

  • 要么你把你的班级分成更小的班级,要么
  • 只是更好地隐藏你的代码,因为你不必透露你的实习生,甚至应该尽可能地隐藏它们!
于 2010-07-09T12:11:06.060 回答