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

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

爪哇:

String property = this.property;

PHP:

$property = $this->property;

或者你会这样做:

爪哇:

String property = this.getProperty();

PHP:

$property = $this->getProperty();

如果我的 Java 有点不对劲,请原谅我,自从我用 Java 编程以来已经有一年了......

编辑:

人们似乎认为我只是在谈论私有或受保护的变量/属性。当我学习面向对象时,我被教导要对每个属性使用 getter/setter,即使它是公共的(实际上我被告知永远不要将任何变量/属性设为公共)。所以,我可能从一开始就从一个错误的假设开始。似乎回答这个问题的人可能会说你应该拥有公共财产,并且那些不需要 getter 和 setter,这违背了我所学的以及我正在谈论的内容,尽管也许需要讨论为出色地。不过,对于另一个问题来说,这可能是一个很好的话题......

有帮助吗?

解决方案

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

其他提示

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

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

我对这种观点如此一致感到相当惊讶 getters 二传手都很好。我推荐艾伦·霍鲁布(Allen Holub)的煽动性文章“Getters 和 Setters 都是邪恶的”。诚然,这个标题是为了令人震惊,但作者的观点是有道理的。

本质上,如果你有 getterssetters 对于每一个私人领域,你都将这些领域变得与公共领域一样好。您将很难更改私有字段的类型而不会对调用该字段的每个类产生连锁反应 getter.

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

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

然而,getter 和 setter 是层边界上不可避免的祸害——UI、持久性等等。限制对类内部的访问,例如C++的friend关键字、Java的包保护访问、.NET的内部访问以及 朋友类模式 可以帮助您降低可见度 getters 并且设置器只提供给那些需要它们的人。

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

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

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

  1. 验证可以放在 setter 中(也可以放在 getter 中)
  2. 智能感知使用显式方法
  3. 不问属性是只读、只写还是读写
  4. 检索虚拟属性(即计算值)看起来与常规属性相同
  5. 您可以轻松设置一个从未在任何地方实际定义的对象属性,然后该属性就不会被记录

我在这里太过分了吗?

也许 ;)

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

PHP:

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

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

然后从对象本身内部:

PHP:

$name = $this->_getName();

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

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

综上所述,getter 应该调用 getter,getter 也应该调用 getter。

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

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

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

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

2) 在某些情况下,这些访问器方法可能不仅仅只是访问字段;他们可能会进行一些额外的处理(尽管这种情况很少见)。如果是这种情况,通过直接访问该字段,您将错过额外的处理,并且如果始终在这些访问期间执行此处理,您的程序可能会出错

纯粹的面向对象方法是避免两者并遵循 德墨忒耳定律 通过使用 告诉不要问 方法。

而不是获取对象属性的值, 紧紧地结合在一起 两个类,使用对象作为参数,例如

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

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

  doSomethingWithProperty( this.daysPerWeek() ) ;

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

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

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

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

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

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

这取决于。这更多的是一个风格问题,而不是其他任何问题,并且没有硬性规则。

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

好吧,看来 C# 3.0 属性的默认实现已经为您做出了决定;您必须使用(可能是私有的)属性设置器来设置属性。

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

我喜欢这个答案 姆卡洛, ,但似乎最正确的是答案 格雷格·赫尔曼. 。如果您从一开始就开始使用 getter/setter 和/或习惯使用它们,请始终使用 getter/setter。

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

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

可能会出现相反的情况,如果您使用 getter/setter 并且有人更改了 getter/setter,他们必须分析内部使用 getter 和 setter 的所有位置,看看是否会弄乱某些东西。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top