【问题标题】:Java getter/setter style questionJava getter/setter 风格问题
【发布时间】:2010-02-08 20:39:18
【问题描述】:

我有一个关于 Java 风格的问题。多年来我一直在编写 Java 编程,但主要是为了我自己的目的,在那里我不必太担心风格,但我只是没有一份必须专业使用它的工作。我之所以这么问,是因为我要让人们第一次真正检查我的代码,我希望看起来我知道自己在做什么。呵呵。

我正在开发一个其他人将在我的工作中使用的库。其他代码使用我的库的方式本质上是实例化主类,并可能在其中调用一两个方法。他们不必使用我的任何数据结构或我在后台使用的任何类来完成工作。我可能会是维护这个库的主要人,但其他人可能会每隔一段时间看看代码。

所以当我编写这个库时,我只是对我的大部分字段使用默认的无修饰符访问级别,甚至让其他类偶尔读取和可能直接从/写入这些字段。由于这是在我的包中,这似乎是一种不错的做事方式,因为这些字段不会从包外部可见,而且似乎没有必要将其设为私有并提供 getter 和 setter。除了我之外没有人会在我的包中编写代码,这是封闭源代码等。

我的问题是:这对其他 Java 程序员来说会是一种糟糕的风格吗?即使我确切地知道将获取和设置我的字段并且我不担心其他人编写的东西会破坏我的代码,我是否应该提供 getter 和 setter?

【问题讨论】:

    标签: java coding-style


    【解决方案1】:

    即使在您的闭源包中,封装也是一个好主意。

    想象一下,你的包中的一堆类正在访问一个特定的属性,而你意识到你需要缓存那个属性,或者记录对它的所有访问,或者从一个实际存储的值切换到你需要的值即时生成。您必须更改许多实际上不应该更改的类。您将一个类的内部工作原理暴露给不需要了解这些内部工作原理的其他类。

    【讨论】:

    • 或者,您可以在所有情况下使用 AOP。
    • 另外,在精神方面,一目了然地掌握私有变量更容易。您会立即知道它的局限性,除非 THIS FILE 中的某些内容对其进行了更改,否则这将无法更改。放弃节省输入几个字符的能力似乎是犯罪——我不会与故意这样做的人一起工作——我不得不假设他在编程时根本没有考虑下一个程序员.
    【解决方案2】:

    我会坚持一个共同的风格(在这种情况下提供 setter/getter)。为什么?

    1. 当您与其他人一起工作或为第 3 方提供库时,这是一种很好的做法
    2. 许多 Java 框架都采用 getter/setter 约定,并被用于查找/公开/询问它们。如果您不这样做,那么您的 Java 对象就会与这些框架和库隔离开来。
    3. 如果您使用 setter/getter,您可以轻松地重构它们背后的内容。仅直接使用字段会限制您执行此操作的能力。

    采用“只为我”的方法确实很诱人,但有很多约定是因为东西利用了它们,并且/或者是出于某种原因的良好做法。我会尽量遵循这些。

    【讨论】:

    • 至于2,也是JavaBean规范的一部分。
    【解决方案3】:

    我认为一个好的语言不应该有任何级别的访问权限,除了私有的——我不确定我是否看到了好处。

    另一方面,也要小心 getter 和 setter——它们有很多陷阱:

    • 他们倾向于鼓励糟糕的 OO 设计(您通常希望您的对象为您做某事,而不是根据它的属性采取行动)
    • 这种糟糕的 OO 设计会导致与您的对象相关的代码散布在不同的对象中,并经常导致重复。
    • setter 使您的对象可变(如果可以的话,最好避免这样做)
    • setter 和 getter 暴露了您的内部结构(如果您有一个用于 int 的 getter,那么以后很难将其更改为双精度 - 您必须触摸它访问的每个位置并确保它可以处理双精度而不会溢出/导致错误,如果您刚开始要求您的对象操作该值,则唯一的更改将在您的对象内部。

    【讨论】:

    • 顺便说一句——我不确定我是否看到公共 FINAL 变量和带有 getter 的变量之间存在巨大差异,除了程序员倾向于喜欢“规则”和 setter/getter“规则"是一个容易理解和落后的问题。从技术上讲,几乎没有理由在公共 final 字段上使用 getter——考虑到如今的重构工具,事实上,我想说从技术上来说绝对没有理由——但你仍然会吓坏很多程序员就像规则一样。
    【解决方案4】:

    大多数 Java 开发人员更愿意看到 getter 和 setter。

    可能没有人在开发您的包中的代码,但其他人正在使用它。通过公开一个明确的公共接口,您可以保证外部消费者按照您的预期使用您的接口。

    如果你公开一个类的内部实现:

    • 无法防止消费者不当使用类
    • 对入口/出口点失去控制;任何公共字段都可能随时发生变化
    • 增加内部实现与外部消费者之间的耦合

    维护 getter 和 setter 可能需要更多时间,但提供了更多安全性:

    • 只要不破坏公共 API(getter、setter 和公共方法),您可以随时重构您的代码,随心所欲。
    • 单元测试封装良好的类更容易 - 您测试公共接口,仅此而已(只需输入/输出到“黑匣子”)
    • 继承、组合和接口设计都将变得更有意义,并且使用解耦类更容易设计
    • 决定在设置mutator之前需要对其添加一些验证?一个好地方是在二传手内。

    由您决定这些好处是否值得花费额外的时间。

    【讨论】:

      【解决方案5】:

      我不太在意样式本身(或任何类型的教条),而是在 可维护性 中使用一组 getter/setter 方法带来的便利。如果您(或其他人)稍后需要更改与更改这些属性之一相关的行为(记录更改、使其成为线程安全、清理输入等),但已经在许多其他地方直接修改了它们在你的代码中,你会希望你使用 getter 和 setter 方法。

      【讨论】:

        【解决方案6】:

        我非常不愿意对除私有字段之外的任何内容进行代码审查,为了子类的利益而保护字段可能除外。它不会让你看起来很好。

        当然,我认为从 Java 专家的角度来看,你可以证明偏离风格是合理的,但由于这是你使用 Java 的第一份专业工作,所以你并不真正处于那个位置。

        所以直接回答你的问题:“这会不会看起来很糟糕?”是的,它会的。

        您的决定合理吗?只有当你真的确信这段代码不会去任何地方时。在典型的商店中,可能有机会重用代码,将事物分解到实用程序类中,等等。如果没有重大更改,该代码将不会成为候选代码。其中一些更改可以通过 IDE 自动化,并且基本上风险很低,但如果您的库处于稳定、经过测试和在生产中使用的地步,那么封装以后将被视为比需要的风险更大。

        【讨论】:

        • 谢谢,直接的答案就是我想要的。使用其他答案中列出的 getter 和 setter 有很多非常好的理由。我有自己的理由来打破封装,并想知道这是否会成为其他 Java 程序员真正关心的事情。
        【解决方案7】:

        由于您是封闭源代码包/库中唯一一个编写代码的人,因此我认为您不必过多担心样式 - 只做最适合您的。

        但是,对我来说,我尽量避免直接访问字段,因为这会使代码更难维护和阅读——即使我是唯一的维护者。

        【讨论】:

          【解决方案8】:

          风格是一个约定俗成的问题。只要一致,就没有正确答案。

          我不是骆驼的粉丝,但在 Java 世界中,camelStyle 规则至高无上,所有成员变量都应该是私有的。

          getData();
          setData(int i);
          

          遵循 Sun (cough Oracle) 的官方 Java 代码约定,应该没问题。

          http://java.sun.com/docs/codeconv/

          【讨论】:

          • +1 用于链接到代码约定,我一直需要类似的东西
          【解决方案9】:

          简而言之,您说“我之所以问,是因为我即将让人们第一次真正检查我的代码,并且我希望看起来我知道自己在做什么”。所以,改变你的代码,因为它确实让你看起来不知道你在做什么。

          您提出它的事实表明您意识到它可能看起来很糟糕(这是一件好事),而且确实如此。正如已经提到的,为了权宜之计,您正在打破 OO 设计的基础。这只会导致代码脆弱且通常无法维护。

          【讨论】:

            【解决方案10】:

            尽管很痛苦,但如果您打算在 JSP(特别是表达式语言)、OGNL 或其他模板语言等上下文中使用对象,则使用 getter 和 setter 编写属性是一个巨大的胜利。如果您的对象遵循良好的旧 Bean 约定,那么以后很多事情都会“正常工作”。

            【讨论】:

              【解决方案11】:

              我发现 getter 和 setter 是更好的编程方式,而不仅仅是编码约定的问题。没有人知道未来,所以我们今天可以写一个简单的字符串电话号码,但明天我们可能不得不在区号和号码之间加上“-”,在这种情况下,如果我们定义了一个 getPhonenumber() 方法,我们可以这样做这样的美化很容易。 所以我想,我们应该始终遵循这种编码风格以获得更好的可扩展性。

              【讨论】:

                【解决方案12】:

                打破封装是个坏主意。所有字段都应该是私有的。否则,类本身不能确保保留自己的不变量,因为某些其他类可能会不小心以错误的方式修改字段。

                为所有字段设置 getter 和 setter 也是一个坏主意。具有 getter 和 setter 的字段与公共字段几乎相同 - 它公开了类的实现细节并增加了耦合。使用这些 getter 和 setter 的代码很容易违反 OO 原则,并且代码变得程序化。

                编写代码时应遵循Tell Don't Ask。例如,您可以通过 Object Calisthenics 练习来练习它。

                【讨论】:

                  【解决方案13】:

                  有时我会使用public final 属性而不使用 get/setter 来处理只携带一些数据的短期对象(并且在设计上永远不会做任何其他事情)。

                  在此之后,如果 Java 隐含使用 property 关键字创建的 getter 和 setter,我真的很高兴...

                  【讨论】:

                    【解决方案14】:

                    正如 JacobM 已经指出的那样,即使对于封闭源代码,使用封装也是一个好主意。但是,如果您的代码充当其他应用程序的库,则您不能阻止其他应用程序访问为内部使用而定义的类。换句话说,您不能(?)强制限制公共类 X 只能由我的应用程序中的类使用。

                    这是我喜欢 Eclipse 插件架构的地方,您可以在其中说明我的插件中的哪些包可以依赖插件在运行时访问。 JSR 277 旨在将这种模块化特性引入 JDK,但现在它已经死了。在这里阅读更多关于它的信息, http://neilbartlett.name/blog/2008/12/08/hope-fear-and-project-jigsaw/

                    现在唯一的选择似乎是 OSGi。

                    【讨论】:

                      【解决方案15】:

                      虽然我很清楚在任何地方都使用 getter 和 setter 的普遍压力,而且代码审查过程让我别无选择,但我仍然不相信这个想法的普遍有用性。

                      原因,对于数据承载类,十多年的发展对我来说从来没有一个案例我会写任何不同的东西,而不是在 setter 中设置变量并在 getter 中读取变量,而很多时间一直花在生成、理解和维护这个似乎没有任何意义的货物崇拜代码上。

                      数据类是一个结构或记录,而不是一个类。它本身不做任何事情。其他类正在对其进行更改。它根本不应该有任何功能,更不用说 setter 或 getter 中的功能了。对于没有方法的多字段数据记录,Java 可能需要一个单独的关键字。

                      从另一方面来看,这个过程现在似乎已经过去了,从一开始就放置 getter 和 setter 可能很有意义,即使是第一次进入新团队也是如此。重要的是不要与团队发生冲突。

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 2010-10-20
                        • 1970-01-01
                        • 2019-01-12
                        • 1970-01-01
                        • 2014-09-13
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多