9

在 Java 类中,使用 getter 和 setter 访问成员字段是好还是坏?

例如哪个更好:

public Order {
    private Agreement agreement;

    public Agreement getAgreement() {
    return agreement;
    } 

    public void process() {
       //should I use:
       getAgreement().doSomething();
       //Or:
       agreement.doSomething();
    }
}

一般来说,由于 KISS 原则,我认为直接访问该字段是最好的,并且稍后有人可能会覆盖 get 方法,结果无法预测。

然而,我的同事认为最好保留一层抽象。对此是否有共识?

4

11 回答 11

9

老实说,在我看来,这取决于您使用它的目的。就个人而言,当有疑问时,我总是在其中留下额外的抽象级别,以防我稍后需要在子类中覆盖它。很多时候,我从重写类的痛苦中解脱出来,只是因为我让 getter 或 setter 对覆盖开放。

另一件事是其他客户/程序员可能需要以您尚未想到的方式使用您的类,例如,将协议类从数据库中提取出来。在这种情况下,当他们覆盖您的课程时,您可以让他们(或未来的您)轻松修改检索数据的方式。

因此,除非您绝对确定只有一种方法可以访问该字段,并且它是 100% 直接的,否则最好将值的检索和修改解耦,以便在将来某个时候您可以避免重写困难。

于 2009-07-07T21:47:43.283 回答
8

这里的核心问题是直接字段访问不适合被子类覆盖方法、AOP、动态代理等拦截。根据具体情况,这可能是好事也可能是坏事。我想说在内部使用 getter 和 setter 不是反模式或模式。这取决于情况和班级的设计,这是好事还是坏事。

于 2009-07-07T21:53:04.300 回答
7

我认为一个类的公共接口代表了对状态的封装,因此甚至类的其他工作也从这种封装中受益。

如果您在公共 get 方法中包装了一个字段,那么您这样做是有原因的。也许该方法中存在延迟加载字段或提供审计跟踪的逻辑。无论该方法的原因是什么,您的类很可能也需要该逻辑。

于 2009-07-07T21:42:07.647 回答
4

在我看来,有些人将这个问题解释为关于外部使用的 getter 和 setter;我对 Pablojim 问题的解释是,它是关于在类中使用它们,而不是类直接访问其字段。(这是私人的。)

鉴于此,我与 Jherico 和 patros 在一起;除非有理由不这样做,否则使用类内的直接访问。

于 2009-07-07T22:08:43.753 回答
2

在 Java 中保留一个抽象层是一件好事。

问题是所有直接访问您的成员变量而没有类注意到它的代码不受您的类的控制。

因此,当您决定以一种方式编辑您的类时,例如在一个部门中使用的一个成员永远不应为 0,您必须能够确保仅以确保这一点的方式更改此值。因此,您将为此方法添加一个设置器并将成员更改为私有。但是现在您需要更改所有在没有设置器的情况下访问成员的代码。
如果您知道您正在从类外部更改值,并且只有在您不知道将变量设为私有时才提供 setter,如果您以后需要访问,则可能提供 getter 或 setter。

如果其他对象中的某些方法总是对成员使用 get 然后执行一些计算然后使用 get,它会得到一个反模式。这表明该成员应该在另一个类中,或者该方法需要在这个类中。

有一个 getter 和一个 setter 而不考虑每个成员会破坏封装,这不是一个好的设计选择。对于铁道部内部人员,请阅读本文

于 2009-07-07T21:45:10.667 回答
1

我现在正在做一些让我支持 getter 的事情:我们现在将部分属性移动到“属性包”中,这意味着您不能只引用变量。因此,除了更改 getter 之外,我们还需要更改引用该变量的所有位置。这是要记住的事情。

于 2009-07-07T21:51:56.207 回答
0

这取决于您使用 getter 和 setter 的目的。通常,当我需要对进入一个类的数据进行完整性检查或格式化输出的数据时,我会使用它们。在这方面,我确实使用 getter 和 setter 作为此类和其他可能需要访问其数据的类之间的接口层。

我倾向于编写我的内部代码,以便它知道如何处理此类私有的数据,因此使用它自己的 getter 和 setter 访问它通常是不必要且不受欢迎的。

不过,这完全取决于您如何使用 getter 和 setter。

于 2009-07-07T21:48:16.993 回答
0

我的经验法则是,如果他们做了比设置或返回值更复杂的事情,请使用 setter/getter。否则,不需要它,因为您可以修复由更改成员变量引起的任何问题。

于 2009-07-07T21:49:32.747 回答
0

你是对的,为每个属性变量做所有额外的工作很烦人。为什么语言允许一些如此基本的东西,没有人能做到?然而,不允许直接属性访问有非常令人信服的理由。

我更喜欢 Eiffel 的统一访问原则。您永远不能分配给属性,并且以相同的方式访问属性和函数:

class EXAMPLE
feature
  variable: INTEGER
  variable_function: INTEGER
    do
      result := 4
    end
  variable_two: INTEGER assign variable_assign
  variable_assign (in: INTEGER)
    do
      variable_two := in
    end  
end

feature
test
local
  test: EXAMPLE
  value: INTEGER
do
  create test
  value := test.variable  -- Valid
  value := test.variable_function  -- Valid and same even though it's a function
  test.variable := value -- Invalid
  test.variable_two := value -- Valid, an explicit setter is defined
end
于 2009-07-07T22:06:11.997 回答
0

我认为这是需要根据具体情况考虑的问题。在整个类代码中使用 getter 确实会使它复杂化,并且可能会使它稍微慢一些。但是,它也使其更具可扩展性和可重用性。

如果我能预见到有人可能想用另一个 getter 覆盖我的 getter,我通常会使用 getter。如果它是如此基本和简单以至于它永远没有意义,我通常不使用吸气剂。

如果您编写代码以在没有 getter 的情况下访问变量,请考虑将 getter 函数设置为“final”。这样一来,没有人会试图覆盖您的代码,并想知道为什么它不起作用。(请注意,Spring 和 Hibernate 代理可能会使这成为一个坏主意。)

于 2009-07-09T03:26:11.133 回答
-1

为了使它成为一种反模式,它必须是绝对有害的。我看不出定义 getter 和 setter 有什么害处。最多,这是浪费时间(和打字),这使它毫无意义,但不是反模式。

于 2009-07-07T21:44:22.493 回答