10

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

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

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

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

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

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

Java 的 Sun 代码约定根本没有提到这一点。)

4

6 回答 6

11

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

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

于 2009-09-07T12:46:37.943 回答
6

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

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


我想提出另一个问题: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 重构,它可能是改进算法的机会。所以维护少。
于 2009-09-07T13:14:58.297 回答
5

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

于 2009-09-07T12:48:06.177 回答
4

Josh Bloch 实际上在Effective Java中支持您,他在此提倡对get不打算用作 bean 的事物使用 -less 变体,以提高可读性。当然,并不是每个人都同意布洛赫的观点,但它表明存在支持和反对倾销get. (我认为它更容易阅读,所以如果 YAGNI,放弃get.)

关于size()集合框架中的方法;当您查看最近Enum的具有name()ordinal(). (这可能可以解释为布洛赫是Enum的两位作者之一。☺)

于 2009-09-07T13:51:43.490 回答
2

get-less 模式用于像 scala (和其他语言)这样的语言,具有统一访问原则

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 中可用,则根本不需要该约定。

注意:为了 Java 的口头禅size()getSize()保留的传统错误命名可能是“向后兼容:始终”。

于 2009-09-07T13:14:20.930 回答
0

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

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

于 2009-09-07T18:31:18.137 回答