104

从不是 getter/setter 方法的对象方法中访问对象属性的“纯粹”或“正确”方法是什么?

我知道从对象外部你应该使用 getter/setter,但从内部你会这样做:

爪哇:

String property = this.property;

PHP:

$property = $this->property;

或者你会这样做:

爪哇:

String property = this.getProperty();

PHP:

$property = $this->getProperty();

如果我的 Java 有点偏离,请原谅我,我已经一年没有用 Java 编程了......

编辑:

似乎人们假设我只是在谈论私有或受保护的变量/属性。当我学习 OO 时,我被教导要对每个单独的属性使用 getter/setter,即使它是公开的(实际上我被告知永远不要公开任何变量/属性)。所以,我可能是从一开始的错误假设开始的。似乎回答这个问题的人可能会说你应该拥有公共属性,而那些不需要 getter 和 setter,这与我所学的内容和我所说的内容背道而驰,尽管也许这需要讨论为好。不过,对于不同的问题,这可能是一个很好的话题……

4

18 回答 18

65

这具有宗教战争的潜力,但在我看来,如果您使用的是 getter/setter,您也应该在内部使用它 - 使用两者都会导致维护问题(例如,有人将代码添加到需要每次设置该属性时运行,并且在内部设置该属性而没有调用该设置器)。

于 2008-08-01T16:13:47.600 回答
44

就个人而言,我觉得保持一致很重要。如果您有 getter 和 setter,请使用它们。唯一一次我会直接访问一个字段是当访问器有很多开销时。你可能会觉得你的代码不必要地膨胀了,但它肯定可以在未来省去很多麻烦。经典例子:

稍后,您可能希望更改该字段的工作方式。也许它应该即时计算,或者您可能想为后备存储使用不同的类型。如果您直接访问属性,那么这样的更改可能会一次性破坏大量代码。

于 2008-08-01T18:23:59.040 回答
27

我很惊讶这种情绪是多么一致,getters而且二传手很好。我推荐 Allen Holub 的煽动性文章“ Getters and Setters are Evil ”。当然,标题是为了震撼价值,但作者提出了有效的观点。

从本质上讲,如果您拥有getters并且setters对于每个私有字段,您就可以使这些字段与公共字段一样好。您将很难更改私有字段的类型,而不会对每个调用它的类产生连锁反应getter

此外,从严格的面向对象的角度来看,对象应该响应与其(希望)单一职责相对应的消息(方法)。绝大多数getters并且setters对其组成对象没有意义;Pen.dispenseInkOnto(Surface)对我来说比Pen.getColor().

Getter 和 setter 还鼓励类的用户向对象请求一些数据,执行计算,然后在对象中设置一些其他值,这就是众所周知的过程编程。你最好简单地告诉对象做你首先要做的事情;也称为信息专家成语。

然而,getter 和 setter 在层的边界上是必不可少的——UI、持久性等等。对类内部的限制访问,例如 C++ 的friend 关键字、Java 的包保护访问、.NET 的内部访问以及Friend 类模式,可以帮助您减少getters仅对需要它们的人的可见性和设置器。

于 2008-09-19T00:13:34.160 回答
20

这取决于如何使用该属性。例如,假设您有一个具有 name 属性的学生对象。如果尚未检索到名称,您可以使用 Get 方法从数据库中提取名称。这样,您就可以减少对数据库的不必要调用。

现在假设您的对象中有一个私有整数计数器,用于计算名称被调用的次数。您可能不想从对象内部使用 Get 方法,因为它会产生无效的计数。

于 2008-08-01T16:19:04.283 回答
15

PHP 提供了无数种方法来处理这个问题,包括魔术方法__get__set,但我更喜欢显式的 getter 和 setter。原因如下:

  1. 验证可以放在 setter(和 getter 中)
  2. Intellisense 使用显式方法
  3. 毫无疑问,属性是只读的、只写的还是读写的
  4. 检索虚拟属性(即计算值)看起来与常规属性相同
  5. 您可以轻松设置从未在任何地方实际定义过的对象属性,然后将其变为无证
于 2008-09-24T17:24:17.733 回答
14

我只是在这里过火了吗?

也许 ;)

另一种方法是使用私有/受保护的方法来实际进行获取(缓存/db/etc),并使用一个公共包装器来增加计数:

PHP:

public function getName() {
    $this->incrementNameCalled();
    return $this->_getName();
}

protected function _getName() {
    return $this->name;
}

然后从对象本身内部:

PHP:

$name = $this->_getName();

这样,您仍然可以将第一个参数用于其他用途(例如发送一个标志以指示是否在此处使用缓存数据)。

于 2008-08-01T16:43:30.880 回答
13

我一定错过了这里的重点,为什么要在对象内部使用 getter 来访问该对象的属性?

以此得出结论,吸气剂应该称为吸气剂,吸气剂应该称为吸气剂。

所以我会说在对象方法内部直接访问一个属性,特别是看到在该对象中调用另一个方法(无论如何它只会直接访问该属性然后返回它)只是一个毫无意义的浪费练习(或者我误解了这个问题)。

于 2011-06-04T15:42:09.807 回答
9

如果您的意思是“纯粹主义者”的“最封装”,那么我通常将我的所有字段声明为私有,然后在类本身中使用“this.field”。对于其他类,包括子类,我使用 getter 访问实例状态。

于 2008-08-22T11:15:45.690 回答
9

该问题不需要基于意见的答案。从高内聚、低耦合原理到SOLID原理,它是计算科学几十年来很好地涵盖的主题。

纯粹的,正确的,OO方式是最小化耦合和最大化内聚。因此,两者都应该避免,并遵循得墨忒耳法则,然后使用告诉不要问的方法。

与其获取将两个类紧密耦合的对象属性的值,不如将对象用作参数,例如

  doSomethingWithProperty() {
     doSomethingWith( this.property ) ;
  }

如果属性是本机类型,例如 int,则使用访问方法,将其命名为问题域而不是编程域。

  doSomethingWithProperty( this.daysPerWeek() ) ;

这些将允许您维护封装和任何后置条件或相关不变量。您也可以使用 setter 方法来维护任何前置条件或依赖不变量,但不要陷入将它们命名为 setter 的陷阱,在使用习语时,请回到好莱坞原则来命名。

于 2008-09-24T17:04:35.240 回答
9

最好使用访问器方法,即使在对象内也是如此。以下是我立即想到的要点:

  1. 应该这样做是为了保持与从对象外部进行的访问的一致性。

  2. 在某些情况下,这些访问器方法可能不仅仅是访问字段;他们可能会做一些额外的处理(虽然这种情况很少见)。如果是这种情况,直接访问该字段将意味着您缺少该附加处理,并且如果始终在这些访问期间完成此处理,您的程序可能会出错。

于 2010-01-20T08:32:59.530 回答
8

我可能是错的,因为我是自学者,但我从不在我的 Java 类中使用公共属性,它们始终是私有的或受保护的,因此外部代码必须由 getter/setter 访问。它更适合维护/修改目的。对于内部类代码...如果 getter 方法很简单,我直接使用该属性,但我总是使用 setter 方法,因为如果我愿意,我可以轻松地添加代码来触发事件。

于 2008-08-06T14:43:54.830 回答
8

我发现使用 setter/getter 使我的代码更易于阅读。我也喜欢它在其他类使用这些方法时提供的控件,如果我更改属性将存储的数据。

于 2008-08-18T17:37:01.130 回答
8

具有公共或受保护属性的私有字段。对值的访问应该通过属性,如果它们将在方法中多次使用,则应将其复制到局部变量。当且仅当您对应用程序的其余部分进行如此彻底的调整、摇摆和优化时,通过它们的关联属性访问值已成为瓶颈(我保证,这永远不会发生)如果您甚至开始考虑让属性以外的任何东西直接接触它们的支持变量。

.NET 开发人员可以使用自动属性来强制执行此操作,因为您甚至在设计时都看不到支持变量。

于 2008-08-18T17:43:29.323 回答
8

如果我不编辑该属性,我将使用公共方法get_property(),除非它是特殊情况,例如另一个对象中的 MySQLi 对象,在这种情况下,我将公开该属性并将其称为$obj->object_property.

在对象内部,对我来说它总是 $this->property。

于 2008-08-22T11:34:06.987 回答
8

这取决于。这更像是一个风格问题,没有硬性规定。

于 2008-10-01T10:51:49.700 回答
6

好吧,似乎使用 C# 3.0 属性的默认实现,您可以做出决定;您必须使用(可能是私有的)属性设置器设置属性。

我个人只在不这样做会导致对象处于不太理想的状态时才使用私有成员,例如在初始化或涉及缓存/延迟加载时。

于 2008-08-01T16:56:55.830 回答
6

我喜欢cmcculloh的答案,但似乎最正确的是Greg Hurlman的答案。如果您从一开始就开始使用 getter/setter 和/或您习惯于使用它们,请始终使用 getter/setter。

顺便说一句,我个人发现使用 getter/setter 使代码更易于阅读和以后调试。

于 2008-09-15T09:46:13.973 回答
5

正如一些评论中所述:有时你应该,有时你不应该。私有变量的重要之处在于,当您更改某些内容时,您可以看到它们使用的所有位置。如果您的 getter/setter 做了您需要的事情,请使用它。如果没关系,你自己决定。

相反的情况是,如果你使用 getter/setter 并且有人更改了 getter/setter,他们必须分析 getter 和 setter 在内部使用的所有位置,看看它是否搞砸了。

于 2008-08-01T17:01:27.240 回答