您将如何从对象方法中访问对象属性?[关闭]


96

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

我知道从对象外部您应该使用getter / setter,但是从内部您只需要这样做:

Java:

String property = this.property;

PHP:

$property = $this->property;

还是你会做:

Java:

String property = this.getProperty();

PHP:

$property = $this->getProperty();

原谅我,如果我的Java有点过时了,距离我用Java编程已经一年了...

编辑:

似乎人们以为我只是在谈论私有或受保护的变量/属性。当我学习面向对象时,我被教导即使每个属性都是公共的,也要对每个属性都使用吸气剂/设置器(实际上,我被告知永远不要公开任何变量/属性)。因此,我可能一开始就从一个错误的假设开始。似乎回答这个问题的人可能是在说您应该拥有公共财产,而那些人不需要吸气剂和塞子,这与我所教的内容和我所谈论的内容背道而驰,尽管也许需要将其讨论为好。不过,这可能是另一个问题的好话题...

Answers:


62

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


除了设置属性的值(在Java中使用错误的示例)外,在setter中没有执行其他任何操作。
euphoria83

1
@ euphoria83也许,但这并不排除它发生的可能性。
Greg Hurlman

我同意原始答案。但是,请记住,如果要在类或对象内进行设置或获取私有内容,则需要确保getter / setter并非周期性的或多余的,否则会导致代码失败。如果您不能使用getter / setter,请直接访问它。(例如,您的getter / setter访问辅助(私有/受保护的)方法来处理数据。)
Rick Mac Gillis

43

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

稍后,您可能希望更改该字段的工作方式。也许应该即时计算,或者您想为后备商店使用其他类型。如果您直接访问属性,则这样的更改可能会在大量涌现中破坏大量代码。


26

我对这种情绪有多么一致感到惊讶,getters而二传手也很好。我建议艾伦·霍鲁布(Allen Holub)撰写的煽动性文章“ 吸气吸毒者和吸毒者都是邪恶的 ”。诚然,标题是为了震撼价值,但作者提出了有效的观点。

本质上,如果您拥有getters并且setters对于每个私有领域,您都在使这些领域与公共领域一样好。您很难改变私有字段的类型,而不会给调用它的每个类带来连锁反应getter

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

Getter和Setter还鼓励类的用户向对象询问一些数据,执行计算,然后在该对象中设置其他值,这被称为过程编程。首先,最好告诉对象要做您打算做的事情。也称为信息专家习惯用法。

但是,getter和setter是在层边界上必不可少的弊端-UI,持久性等。限制对类内部的访问,例如C ++的friend关键字,Java的程序包保护的访问,.NET的内部访问以及Friend Class Pattern,可以帮助您减少getters只有需要它们的人的访问权限和设置程序。


19

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

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


如果Student对象是业务/域对象,那么您现在正在混合基础结构详细信息。理想情况下,业务/域对象应仅与业务/域逻辑有关。
moffdub's

如果在getter中添加某种布尔值,该怎么办:PHP:公共函数getName($ outsideCall = true){if($ outsideCall){$ this-> incrementNameCalled(); }返回$ this-> name; },然后在对象本身内部,如果您调用get name,则可以通过以下方式阻止它递增:PHP:$ name = $ this-> getName(false); 我只是在这里过分吗?
cmcculloh

14

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

  1. 可以将验证放置在setter(以及与此相关的getter)中
  2. Intellisense使用显式方法
  3. 毫无疑问,属性是只读,只写还是读写
  4. 检索虚拟属性(即计算值)看起来与常规属性相同
  5. 您可以轻松地设置一个从未在任何地方定义的对象属性,然后该属性将不再记录

13

我只是在这里过分吗?

也许 ;)

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

PHP:

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

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

然后从对象本身内部:

PHP:

$name = $this->_getName();

这样,您仍然可以将第一个参数用于其他内容(例如发送标记,以了解此处是否使用了缓存的数据)。


12

我必须在这里遗漏一点,为什么要在对象内使用吸气剂访问该对象的属性?

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

因此,我想说一个对象方法内部直接访问属性,尤其是看到调用该对象中的另一个方法(无论如何将直接访问该属性然后返回它)只是没有意义的浪费的练习(或者我误解了这个问题) )。


我也被您不得不评论的同样的需求所驱动...另外,它的回答没有关闭;)
Egg Vans 2013年

8

纯粹的面向对象方法是避免两者,并通过使用“不要问”方法遵循Demeter法则

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

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

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

  doSomethingWithProperty( this.daysPerWeek() ) ;

这些将使您能够维护封装以及任何后置条件或因变量。您也可以使用setter方法来维护任何前提条件或相关不变量,但是不要陷入为它们指定命名器的陷阱,使用成语时,请返回Hollywood原则进行命名。


8

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

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

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


8

如果您用“纯粹主义者”来表示“大多数封装”,那么我通常将所有字段声明为私有字段,然后在类本身内部使用“ this.field”。对于其他类(包括子类),我使用getter访问实例状态。


7

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


7

具有公共或受保护属性的私有字段。对值的访问应通过属性,如果在方法中将多次使用它们,则应将其复制到局部变量。如果并且仅当您对应用程序的其余部分进行了完全调整,精简和优化,以至于无法通过访问它们的关联属性来访问值成为瓶颈(而且我保证永远不会发生),即使您开始考虑让属性以外的任何内容直接接触其后备变量。

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



7

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


7

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

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


5

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

我本人仅在不使用私有成员的情况下使用私有成员,否则会导致对象处于不太理想的状态,例如在初始化时或在涉及缓存/延迟加载时。


5

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

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


4

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

可能出现相反的情况,如果您使用吸气剂/塞特而有人更改了吸气剂/塞特,则他们必须分析内部使用吸气剂和塞特剂的所有位置,以查看是否弄乱了某些东西。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.