【问题标题】:How important are naming conventions for getters in Java?Java 中 getter 的命名约定有多重要?
【发布时间】:2009-09-07 12:42:13
【问题描述】:

我非常相信一致性,因此也是惯例。

但是,我目前正在用 Java 开发一个框架,其中这些约定(特别是 get/set 前缀约定)似乎妨碍了可读性。例如,某些类将具有idname 属性,并且使用o.getId() 而不是o.id() 似乎完全没有意义,原因有很多:

  • 类是不可变的,因此(通常)不会有相应的 setter,
  • 没有混淆的可能,
  • 在这种情况下,get 没有传达额外的语义,并且
  • 我在整个库中非常一致地使用这种get-less 命名模式。

Java Collection 类(以及 Java 平台库中的其他类)也违反了 JavaBean 约定(例如,它们使用 size 而不是 getSize 等),这让我得到了一些保证。

为了解决这个问题:组件将永远被用作 JavaBean,因为它们不能以这种方式有意义地使用。

另一方面,我不是一个经验丰富的 Java 用户,我不知道其他 Java 开发人员对库的期望。我可以按照 Java 平台类的示例进行操作,还是认为它的风格不好?回想起来,Java 库类中违反 get/set 约定是否被视为错误?或者在不适用时忽略 JavaBean 约定是否完全正常?

Sun code conventions for Java 根本不提这个。)

【问题讨论】:

    标签: java naming-conventions javabeans


    【解决方案1】:

    如果您遵循适当的命名约定,则第 3 方工具可以轻松地与您的库集成并使用。他们会期待getX()isX() 等,并尝试通过反思找到这些。

    虽然您说这些目前不会作为 JavaBeans 公开,但我仍然会遵循约定。谁知道你可能想进一步做些什么?或者在稍后阶段,您可能想要提取到该对象的接口并创建一个可以通过其他工具访问的代理?

    【讨论】:

    • 这里绝对同意——许多框架(例如,JSF)将完全无法工作,除非您遵循约定。它是 java bean 标准,但它已成为许多层的通用约定。偏离标准是危险的,只有在有充分理由的情况下才能这样做。信号不变性不算在内。
    • @Tim:信号不变性实际上并不是我反对遵循约定的论点,不变性只是不遵守约定的一个原因(实际原因是 get 对程序员来说在语义上是多余的)。不过,有效点数。
    【解决方案2】:

    我真的很讨厌这种约定。如果它被一个提供访问器/修改器方法的真正的 java 工具取代,我会很幸运。

    但我的所有代码都遵循这个约定。我们不是单独编程,即使整个团队现在都同意一个特别的会议,你可以放心,未来的新人,或者维护你项目的未来团队,一开始会很艰难......我相信 get/set 带来的不便没有非标准带来的不便那么大。


    我想提出另一个问题:java 软件经常使用太多的访问器和修饰符(get/set)。我们应该更多地应用“告诉,不要问”的建议。例如,将 B 上的 getter 替换为“真实”方法:

        class A {
          B b;
          String c;
          void a() {
            String c = b.getC();
            String d = b.getD();
            // algorithm with b, c, d
          }
        }
    

    通过

        class A {
          B b;
          String c;
          void a() {
            b.a(c); // Class B has the algorithm.
          }
        }
    

    这个重构获得了很多好的属性:

    • B 可以设为不可变(非常适合线程安全)
    • B 的子类可以修改计算,因此 B 可能不需要其他属性来达到此目的。
    • 在 B 中的实现比在 A 中更简单,因为您不必使用 getter 和外部访问数据,您在 B 内部并且可以利用实现细节(检查错误、特殊情况下,使用缓存值...)。
    • 位于与它有更多耦合的 B 中(两个属性而不是 A 的一个属性),重构 A 可能不会影响算法。对于 B 重构,它可能是改进算法的机会。所以维护更少。

    【讨论】:

      【解决方案3】:

      Java 库类中违反 get/set 约定肯定是一个错误。我实际上建议您遵循约定,以避免知道为什么/何时不遵守约定的复杂性。

      【讨论】:

      • 完全正确;标准的 Java API 类当然不是完美和一致的。 (例如,有些有方法 size(),而另一些有方法 length())。不要将标准 API 类作为如何做事的完美示例。
      • @Jesper:当然,但是 new 集合类是非常优秀 API 设计的一个例子,它具有很多远见和伟大一致性程度(暂时忽略向后兼容性)。
      【解决方案4】:

      Josh Bloch 实际上在 Effective Java 中支持你,他在其中提倡 get-less 变体用于不打算用作 bean 的东西,以提高可读性.当然,并不是每个人都同意 Bloch,但它表明有支持和反对倾销 get 的案例。 (我认为它更容易阅读,所以如果是 YAGNI,请放弃 get。)

      关于集合框架中的size() 方法;当您查看具有name()ordinal() 的较新的Enum 类时,它似乎不太可能只是一个“坏”的传统名称。 (这可能可以解释为 Bloch 是 Enum 的两位作者之一。☺)

      【讨论】:

      • 这正是我的观点:不幸的是,由于缺乏经验,我无法确定是否为 IAGNI。现在,我将吞下苦果并使用getXXX。但是感谢您提到布洛赫对此的看法,我非常尊重那个家伙。
      • 就像事后分析一样:我应该没有 get 前缀,在我的情况下它完全没用。豆子?从来没有用过。
      【解决方案5】:

      get-less 架构用于像 scala(和 other languages)这样的语言,Uniform Access Principle

      Scala 将字段名和方法名保留在同一个命名空间中,这意味着如果方法名为 count,我们无法命名字段 count。许多语言(如 Java)没有此限制,因为它们将字段和方法名称保存在不同的命名空间中。

      由于 Java 并不打算为“属性”提供 UAP,因此最好使用 get/set 约定来引用这些属性。

      UAP 的意思是:

      • Foo.barFoo.bar() 相同,指的是读取属性,或者是读取属性的方法。
      • Foo.bar = 5Foo.bar(5) 是一样的,都是指设置属性,或者是属性的写入方法。

      在 Java 中,您无法实现 UAP,因为 Foo.barFoo.bar() 位于两个不同的命名空间中。
      这意味着要访问 read 方法,您必须调用 Foo.bar(),这与调用任何其他方法没有什么不同。
      因此,这个 get-set 约定可以帮助将该调用与其他调用区分开来(与属性无关),因为模块提供的“所有服务(此处为“仅读取/设置一个值,或计算它”)不能通过统一符号”。
      这不是强制性的,但它是一种从其他服务中识别与获取/设置或计算属性值相关的服务的方法。
      如果 UAP 在 Java 中可用,则根本不需要该约定。

      注意:size() 而不是 getSize() 可能是一个遗留的错误命名,因为 Java 的口头禅是“向后兼容:始终”。

      【讨论】:

      • 我不明白这一点:“由于 Java 不打算为“属性”提供 UAP,因此最好使用 get/set 约定来引用这些属性。” ——肯定相反吗? Scala 与 Java 不同,不能 为属性重载名称,由于缺少 UAP,只有 Java 可以。我不明白为什么我应该使用 get 前缀。
      【解决方案6】:

      考虑一下:可以告诉许多框架引用对象字段中的属性,例如“名称”。在底层,框架理解首先将“name”转换为“setName”,从其单数参数中找出返回类型是什么,然后形成“getName”或“isName”。

      如果您不提供这种有据可查、合理的访问器/修改器机制,您的框架/库将无法与大多数其他库/框架一起使用。

      【讨论】:

      • @Esko:是的,这就是我的问题的症结所在:这些是什么框架,它们重要吗?我已经提到我的类作为 bean 没有意义,而且我有限的 Java 经验从未处理过任何其他此类库。如果有人能指出相关的例子,我会非常高兴(蒂姆已经做到了,在对已接受答案的评论中)。
      • ...(续)显然 Josh Bloch 在设计 Collections 库时并不认为这是一个主要障碍。我的图书馆在某些方面是相似的。
      • 几乎所有被认真对待的框架。 get/set 范例的要点是,如果您需要访问或改变对象的内部状态,请使用它们。甚至 Collections 也以这种方式工作;但是集合不是豆子。
      • JavaBeans 与我作为 Android 开发人员完全无关,尽管我仍在使用 Java。问题是关于 Java 的,对于纯 Java,在所有 getter 前面加上 get* 没有真正的价值。为简化某些框架而调整代码约定绝对是一个缺陷。
      • @Alexi 虽然这个答案已经很老了,但它仍然存在 - JVM 没有真正的成员属性(不像 CLR),这意味着获取属性的唯一方法类似的功能是使用 set/get 方法。
      猜你喜欢
      • 2011-03-13
      • 2011-02-26
      • 1970-01-01
      • 2020-05-15
      • 2013-08-05
      • 2018-06-10
      相关资源
      最近更新 更多