getter和setter经常被批评为不合适的OO。另一方面,我见过的大多数OO代码都有大量的getter和setter方法。

何时使用吸气剂和塞特剂?您是否尝试避免使用它们?它们是否普遍使用过度?从OO方法论的角度来看,它们是同一回事。它们只是语法更好。

Getter / Setter批评的来源(摘自一些注释,以使他们更清晰可见):


http:// www。 javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html
http://typicalprogrammer.com/?p=23
http://c2.com/cgi/wiki AccessorsAreEvil
http://www.darronschall.com/weblog/2005/03/no-brain-getter-and-setters.cfm
http://www.adam-bien.com/roller / abien / entry / encapsulation_violation_with_getters_and
http://www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html

简单地提出批评:使用Getter和Setter可以从对象外部操纵对象的内部状态。这违反了封装。只有对象本身才应该关心其内部状态。

和示例
程序版本的代码。

struct Fridge
{
    int cheese;
}

void go_shopping(Fridge fridge)
{
     fridge.cheese += 5;
}


Mutator版本的代码:

class Fridge
{
     int cheese;

     void set_cheese(int _cheese) { cheese = _cheese; }
     int get_cheese() { return cheese; }
 }

void go_shopping(Fridge fridge)
{
     fridge.set_cheese(fridge.get_cheese() + 5);        
}


吸气器和设置器使代码复杂得多,而没有适当的封装。由于其他对象可以访问内部状态,因此添加这些getter和setter并不会带来很多好处。
https://stackoverflow.com/questions/565095/java-are-getters-and-setters-evil
https://stackoverflow.com/questions/996179


评论

吸气器和装夹器经常被批评为不合适的面向对象-请引文。

@Robert Harvey:Typicalprogrammer.com/?p = 23 | javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html | darronschall.com/weblog/2005/03/no-brain-getter-and-setters.cfm | adam-bien.com/roller/abien/entry / ...

@Job,为什么因为有代码?如果认真对待的话,这是一个很好的问题和圣战的隐患。

@Winston Ewert:“ ...问题是,是否应该访问类中的数据。”:嗯,没有人强迫您为所有成员变量实现getter和setter方法,而仅实现所需的变量。这就是为什么您使用getter和setter而不是public成员变量的原因。
@Winston Ewert:我不知道缺少getters / setters怎么解决这个问题:必须有一种访问每条数据的方法,否则它是无用的。一个好的设计的任务是确定哪一部分数据可访问代码的哪一部分。如果一个设计师不好,那么他或她将会有或没有getter和setter。就是我的2美分。

#1 楼

拥有getter和setter方法本身并不会破坏封装。破坏封装的方法是自动为每个数据成员(Java术语中的每个字段)添加一个getter和setter,而无需考虑任何问题。尽管这比公开所有数据成员更好,但只有一小步之遥。

封装的要点不是说您不应该知道或更改对象的从对象外部声明,但您
应该有合理的政策来做到这一点。


某些数据成员可能完全在对象内部,并且应该
既没有getter也没有setter。
有些数据成员应该是只读的,因此它们可能需要吸气剂,但某些数据成员可能需要保持一致。在这种情况下,您将不会为每个设置器提供一个设置器,而是提供一个用于同时设置它们的单个方法,以便您可以检查
值的一致性。 />某些数据成员可能只需要以某种方式进行更改,例如
以固定量递增或递减。在这种情况下,您
将提供一个increment()和/或decrement()方法,而不是一个setter。
其他人实际上可能需要被读写,并且同时具有getter br />和setter。

考虑class Person的示例。假设一个人有名字,社会保险号和年龄。假设我们不允许人们更改其姓名或社会保险号。但是,该人的年龄每年应增加1。在这种情况下,您将提供一个构造函数,该构造函数会将名称和SSN初始化为给定值,并将年龄初始化为0。您还将提供方法incrementAge(),该方法会将年龄增加1。为这三个提供吸气剂。在这种情况下,不需要二传手。

在此设计中,允许从类外部检查对象的状态,并允许从类外部更改对象的状态。但是,您不允许随意更改状态。有一项策略有效地声明了名称和SSN完全不能更改,并且年龄可以一次增加1年。

现在,假设一个人也有薪水。人们可以随意更换工作,这意味着他们的工资也将改变。为了模拟这种情况,我们只能采用setSalary()方法!在这种情况下,允许随意更改工资是一个完全合理的政策。

在您的示例中,我将为Fridge类提供putCheese()takeCheese()方法,而不是get_cheese()set_cheese()。这样您仍然可以封装。


public class Fridge {
  private List objects;
  private Date warranty;

  /** How the warranty is stored internally is a detail. */
  public Fridge( Date warranty ) {
    // The Fridge can set its internal warranty, but it is not re-exposed.
    setWarranty( warranty );
  }

  /** Doesn't expose how the fridge knows it is empty. */
  public boolean isEmpty() {
    return getObjects().isEmpty();
  }

  /** When the fridge has no more room... */
  public boolean isFull() {
  }

  /** Answers whether the given object will fit. */
  public boolean canStore( Object o ) {
    boolean result = false;

    // Clients may not ask how much room remains in the fridge.
    if( o instanceof PhysicalObject ) {
      PhysicalObject po = (PhysicalObject)o;

      // How the fridge determines its remaining usable volume is a detail.
      // How a physical object determines whether it fits within a specified
      // volume is also a detail.
      result = po.isEnclosedBy( getUsableVolume() );
    }

     return result;
  }

  /** Doesn't expose how the fridge knows its warranty has expired. */
  public boolean isPastWarranty() {
    return getWarranty().before( new Date() );
  }

  /** Doesn't expose how objects are stored in the fridge. */
  public synchronized void store( Object o ) {
    validateExpiration( o );

    // Can the object fit?
    if( canStore( o ) ) {
      getObjects().add( o );
    }
    else {
      throw FridgeFullException( o );
    }
  }

  /** Doesn't expose how objects are removed from the fridge. */
  public synchronized void remove( Object o ) {
    if( !getObjects().contains( o ) ) {
      throw new ObjectNotFoundException( o );
    }

    getObjects().remove( o );

    validateExpiration( o );
  }

  /** Lazily initialized list, an implementation detail. */
  private synchronized List getObjects() {
    if( this.list == null ) { this.list = new List(); }
    return this.list;
  }

  /** How object expiration is determined is also a detail. */
  private void validateExpiration( Object o ) {
    // Objects can answer whether they have gone past a given
    // expiration date. How each object "knows" it has expired
    // is a detail. The Fridge might use a scanner and
    // items might have embedded RFID chips. It's a detail hidden
    // by proper encapsulation.
    if( o implements Expires && ((Expires)o).expiresBefore( today ) ) {
      throw new ExpiredObjectException( o );
    }
  }

  /** This creates a copy of the warranty for immutability purposes. */
  private void setWarranty( Date warranty ) {
    assert warranty != null;
    this.warranty = new Date( warranty.getTime() )
  }
}


评论


请不要太重视我的冰箱示例。 :)真正的冰箱应该是一个容器对象,我希望它知道如何容纳对象而不必担心它们的确切含义。即它就像一个ArrayList。至于使它成为冰箱的原因,可以说它在存储对象时将对象序列化到磁盘上,从而使它们在系统故障中幸免。好。认真地把我的冰箱当作例子。

–温斯顿·埃韦特(Winston Ewert)
2010-11-26 23:40

但是冰箱是否不应该知道失效日期,以便它可以告诉您奶酪已经变质并且应该丢弃? :)好吧,我们必须停止这个! :)

–迪马
2010年11月27日,0:10

您在这里对冰箱逻辑进行了非常有趣的讨论...

–梅森·惠勒
10 Nov 27'6:27

哈哈,我希望看到它的广告:“这是一种全新的冰箱:当试图抓住不存在的东西时,它会向您扔东西!这样,您只会尝试一次!您担心塞满冰箱,让冰箱担心非法行为!”

–加布林
2010-11-27 9:13



该示例完全错误。不应存在​​Age字段或setAge()方法。与某个时间点相比,年龄是人员出生日期的函数。尽管看似微不足道,但这确实是对象完全可变性和其他不良设计的现代实践的错误所在,如专用字段的get / set方法所看到的,而不是仔细考虑真正可变的,字段是什么,对象是什么应该了解其行为以及实际上有效的状态更改(哪些setX方法完全销毁)。

–达雷尔·蒂格(Darrell Teague)
2014年7月21日在18:49



#2 楼

Java中获取和设置方法的基本原因非常简单:


您只能在接口中指定方法,而不能指定字段。

因此,如果要允许字段通过接口传递,您将需要一个reader和writer方法。传统上,它们被称为字段x的getX和setX。

评论


这是语言限制。真正的问题是我们是否应该允许其他对象操纵该状态。

–温斯顿·埃韦特(Winston Ewert)
2010-11-26 23:05

@Peter Turner,显然没有什么可以阻止语言具有包含属性的接口。在幕后,很可能实现为getter / setter,但为属性的接口定义添加支持将很容易。

–温斯顿·埃韦特(Winston Ewert)
2010-11-26 23:54

@Winston,您最终将需要允许类在彼此之间来回传递信息以实际完成工作。您会建议什么呢?

–user1249
10 Nov 27'6:38

一个对象应该为其内部提供更高级别的接口。 Getter和Setter往往是一个低级接口。例如,假设您有一个实现二叉树的类。您可以使用GetLeft(),GetRight(),GetValue()和GetKey()之类的功能来导航树。但这是完全错误的方法。您的二叉树类应提供诸如查找,插入,删除之类的操作。

–温斯顿·埃韦特(Winston Ewert)
2010-11-27 14:51

再举一个例子,考虑一块俄罗斯方块。俄罗斯方块有一些内部状态,例如block_type,rotation,position。您可能拥有诸如GetBlockType(),GetRotation(),GetPosition()之类的吸气剂。但是你真的不应该。您应该拥有一个GetSquares()方法,该方法返回该部件占用的所有正方形的列表。您也不应该拥有SetPosition()或SetRotation()之类的东西。相反,您应该具有MoveLeft(),MoveRight(),Rotate(),Fall()之类的操作。

–温斯顿·埃韦特(Winston Ewert)
2010-11-27 14:55

#3 楼

来自http://www.adam-bien.com/roller/abien/entry/encapsulation_violation_with_getters_and

JavaBean样式:

connection.setUser("dukie");
connection.setPwd("duke");
connection.initialize();


OO-样式:

connection.connect("dukie","duke");


好吧,很明显,我更喜欢后者。它不会泄漏实现细节,它更简单,更简洁,并且所有需要的信息都包含在方法调用中,因此更容易实现。我还更愿意在可能的情况下使用构造函数中的参数设置私有成员。也许当需要更改模式时,或者您需要询问对象以获取某些信息时。

myObject.GetStatus();
myObject.SomeCapabilitySwitch = true;


考虑到这一点,当我第一次开始使用C#进行编码时,用上面说明的Javabeans风格编写了很多代码。但是随着我在语言方面的经验的积累,我开始在构造函数中进行更多的成员设置,并使用看起来更像上述OO风格的方法。

评论


为什么“将所有参数作为参数”为OO样式?

–user1249
2010-11-27 6:39

尽管您的“ OO风格”适合2或3个选项,但一旦您达到了上述目标,我将更喜欢JavaBean风格。对于每种可能的参数组合都有20种重载方法看起来很糟糕

–TheLQ
10-11-27在19:38

@TheLQ:C#4.0通过允许在构造函数和方法调用中使用可选参数和命名参数,使此操作变得更容易。

–罗伯特·哈维(Robert Harvey)
2010-11-27 22:40



@TheLQ这就是使用流利语法的Builder的用途,请参见例如番石榴的MapMaker。

– maaartinus
11年8月6日在16:35

@ThorbjørnRavn Andersen,我想说“将所有参数作为参数”比“调用JavaBean设置器”更好的OO风格,因为设置器暗示设置了底层属性,根据定义,该属性公开内部细节。在示例中使用connect(..)方法没有做出这样的假设;也许您设置了用户和密码属性,也许没有。重要的是要关注正确的面向对象概念:“连接”消息。

– Andres F.
11年11月21日在16:03

#4 楼


什么时候需要进行getter和setter的合理化? >
其他用途只是作弊,因为业务领域的行为尚不明确。

编辑

该答案可能是浮躁的,所以让我扩展。上面的答案大部分是正确的,但侧重于OO设计的编程范例,还有一些遗漏的地方。根据我的经验,这使人们认为避免使用getter和setter是OO编程语言的一些学术规则(例如,人们认为用属性替换getter很重要)

实际上,这是设计过程的结果。您不必深入研究接口,封装和模式,也不必争论它们是否破坏了这些范式以及什么是好的OO编程还是不好的OO编程。最终最重要的一点是,如果您的域中没有通过将它们放入您的域而能够像这样工作的实体,则不会对您的域建模。您的域空间中有getter和setter。您不能走到负责工资单的男人或女人,而只能说“将此薪水设置为X”或“请给我这个薪水”。根本不存在这种行为

如果将其放入代码中,则不是在设计与域模型匹配的系统。是的,这破坏了接口和封装,但这不是重点。关键是您正在建模一些不存在的东西。

您可能还缺少一个重要的步骤或过程,因为可能有一个原因我不能单单支付工资并说将此薪水设置为X。

当人们使用吸气剂和吸气剂时,他们倾向于将这一过程的规则推到错误的地方。这将进一步远离您的域。使用现实世界中的示例,这就像薪水,假设走进的随机人有权获取这些值,否则他不会要求这些值。不仅不是域的方式,而且实际上还在于域的方式。

评论


在先前的17个答案中,这似乎并没有提供任何实质性的解释。

– gna
2014年9月8日上午10:12

其他答案讨论对象,接口和其他语言范例。很好,但这不是中心问题。 Getter和Setter不仅不好,因为它们违反了一些编码约定,而且主要是因为您几乎不会在所表示的实际模型中遇到这种行为。这一点在有关最佳编码实践的讨论中往往会迷失。

– Cormac Mulhall
2014年9月8日在10:42

如果未设置/获取薪水,您认为工资界面是什么?

–温斯顿·埃韦特(Winston Ewert)
2014年9月8日17:50



如果它们围绕授权层包装并且仅限于某些外部实体,则它们不是获取器和设置器。我并不是说薪资部门没有任何改变薪水的方法,但是这种方法应该与公司内部的内部流程保持一致。例如,大多数公司根据员工合同(由经理授权)设置工资。如果员工的薪水发生变化,则应草拟新合同,经理必须签署该合同。因此,工资单应期望合同对象和某些授权对象更改工资单

– Cormac Mulhall
2014年9月9日14:17在

换句话说,set_salary(new_salary,employee_id)和authorized_salary_update(employee_contract,authorising_manager)之间有很大的区别。该流程应为内部业务流程建模

– Cormac Mulhall
2014年9月9日14:23在

#5 楼

通常,吸气剂和吸气剂是个坏主意。如果字段在逻辑上不是接口的一部分,并且您将其设为私有,那很好。如果它在逻辑上是接口的一部分,并且您将其公开,那就很好。但是,如果您将其设为私有,然后通过提供一个getter和setter将其转为有效并再次有效地公开,则您将回到开始的地方,只是您的代码现在变得更加冗长和模糊。

,也有例外。在Java中,您可能需要使用接口。 Java标准库具有向后兼容性的要求,因此其极端性足以超过正常的代码质量度量。甚至有可能您实际上是在处理传奇但罕见的情况,即很有可能以后可以用即时计算替换存储的字段而不会破坏接口。但是这些都是例外。 Getter和Setter是需要特殊证明的反模式。

评论


一个getter和setter表示该属性而不是字段是接口的一部分。假设getBirthDate()和SetBirthDate()取“ yyyy / mm / dd”,但存储的字段是自01/01/1000开始的天数。您可以将其更改为01/01/0001,getter和setter将使接口保持不变。尤其是因为“公共”意味着公开可丢弃,因此变量永远不应公开。始终使用setter验证传入的值,更新任何相关字段,根据需要进行转换等。请尝试使用getter以防内部存储发生更改。

–安迪·坎菲尔德(Andy Canfield)
2011年10月4日7:35



@AndyCanfield可以说公众是公开可垃圾的。.只有当您对它编程不好时,这样才行。如果您有一个setter并且错误的值被发送到它,那么您可能会抛出一个异常,您可以调用该程序来破坏程序,但是它会因错误而退出。此外,如果对象的用户可以给变量赋值,而cud则给定错误的值。值,那么您可以牢记这一点并对其进行测试。您可能会说“啊,但是如果我使用设置器,我只需要进行1次测试”,但是也许您自己的代码给变量赋予了错误的值。所以设置器可能不会减少测试。通过测试,您的编程不会“被破坏”

– barlop
2015年2月1日下午5:31



#6 楼

是直接访问字段还是通过方法访问字段并不重要。

类不变式(有用的)很重要。
为了保护它们,有时我们不能更改某些内容。在外面。
例如如果我们的Square类具有单独的宽度和高度,那么更改其中之一会使它变成不是Square的其他东西。但是setter比会测试它的大于零是否更好。

在具体语言(例如java)中,这就是我们需要这些方法(接口)的原因。方法是兼容性(源和二进制)。因此,添加它们比较容易,然后考虑是否可以使用公共领域。

btw。我喜欢对公共final字段使用简单的不可变值持有类。

评论


这几乎是唯一应避免的事情。从现场到财产/获取者/设定者,对大多数语言来说都是一个重大变化。

– MrDosu
2014年9月16日上午11:13

#7 楼

您可能希望将内部结构更改为任何内容,同时保持接口相同。如果您的界面不变,则您编写的代码不会中断。您仍然可以根据需要更改内部构造。

评论


我很惊讶这个答案如此之遥。使用Getter和Setter可以在不破坏现有API的情况下,在将来做更多的事情(例如,触发事件,进行更多的输入验证,进行内部记账)。即使使用非公开代码,您也需要更改的API更少,要更新的依赖项也更少,并且进行这些更新时引入的错误也更少。

– AmadeusDrZaius
16-4-27 6:00



#8 楼

我的方法是这样-

当我期望以后再使用数据时,使用getter / setter是合理的。另外,如果发生更改,我经常将数据推送到getter / setter中。级别,问题是“谁来管理数据”,这取决于项目。

#9 楼

如果使用getter和setter感到很复杂,那么问题可能出在语言上,而不是概念本身。

这是用Ruby编写的第二个示例中的代码:

class Fridge
  attr_accessor :cheese
end

def go_shopping fridge
  fridge.cheese += 5
end


请注意,它看起来很像Java中的第一个示例?如果将吸气剂和装夹器视为头等舱市民,那么它们就不是一件繁琐的事,而增加的灵活性有时则是真正的好处-例如,我们可以决定在新冰箱上返回奶酪的默认值:

class Fridge
  attr_accessor :cheese

  def cheese
    @cheese || 0
  end
end


当然,会有很多不应该公开暴露的变量。不必要地公开内部变量会使您的代码更糟,但是您几乎不能将其归咎于getter和setter。

评论


这说得很漂亮。添加了生成器功能,因为我们希望在逐步构建配方的同时创建不可变的对象:也许如果添加人造甜味剂,则无需添加糖。使用命名参数,即使有重载,也很难构建一种可以完成所有工作的方法。然后,当然Java没有命名参数,因此,人们使用Builder模式的另一个原因是。

–溜溜球
16年1月13日,0:38

#10 楼

考虑一个封装宽度和高度的Size类。我可以使用构造函数消除设置器,但是如何用Size绘制矩形?宽度和高度不是该类的内部数据;它们是必须供Size的使用者使用的共享数据。

对象由行为和状态-或属性组成。如果没有公开状态,那么只有行为是公开的。

没有状态,如何对对象集合进行排序?您将如何搜索对象的特定实例?如果仅使用构造函数,则当对象的属性列表很长时会发生什么情况?

未经验证,任何方法参数都不应消耗。因此,这样写是很懒惰的:它比公共领域要好-但仅此而已。但是至少您拥有一个一致的公共接口,您可以返回该接口并加入验证规则,而又不会破坏客户的代码。

字母,设置器,属性,更改器,随便叫什么,但是它们是必需的。

评论


但是至少您拥有一个一致的公共接口,您可以返回该接口并放入验证规则,而不会破坏客户的代码。这不是真的。进一步添加验证规则很可能会“破坏客户的代码”。例如,以一个int实例变量为例,假设您决定添加一个验证规则以仅接受非负值。问题是您客户的代码可能已经依赖于将其设置为负值的可能性。

–jub0bs
2015年11月1日14:19



#11 楼

如果getter和setter违反了封装和真正的OO,那么我就很麻烦了。 />我刚刚完成了一个用Java生成迷宫的程序,并且有一个表示“迷宫方块”的类。我在此类中有表示坐标,墙和布尔值等的数据。

我必须有某种方法来更改/操作/访问该数据!没有getter和setter的情况下我该怎么办? Java不使用属性,并且将我在此类中本地的所有数据都设置为public无疑是对封装和OO的违反。

评论


这里的问题是:如果您将所有这些字段都公开,并且停止使用getter和setter,您的代码会有什么不同?

–温斯顿·埃韦特(Winston Ewert)
2010-11-27 15:10

从理论上讲,它不是。为什么还要在那时上课?任何事情都可以提出相同的论点。但是我下面的帖子似乎更优雅地说了。 (字母和设置员是一种将值安全地传递给对象或从该对象检索值的方法。)帖子继续。

–布莱恩·哈灵顿(Bryan Harrington)
2010-11-27 15:14

我要指出的是:那个海报最终同意了我的看法,并发布了另一个答案。本质上,使用getter和setter与直接操作数据相同。这样做并不会真正让您感到OOness。为了成为OO,您应该为数据提供更高级别的接口。

–温斯顿·埃韦特(Winston Ewert)
2010-11-27 15:29

我认为最好的描述方法是说应该从外而内而不是由内而外设计接口。对象提供的接口应由对象的使用方式决定,而不是由对象的实现方式决定。因此,请勿编写吸气剂并允许外部对象解释数据。找出他们需要回答什么问题,并编写回答该问题的方法。不允许外部对象通过设置器修改状态,不要发现它们需要执行哪种操作并编写执行该操作的方法。

–温斯顿·埃韦特(Winston Ewert)
2010-11-27 15:31

在某些情况下,Getters和Setters是最好的方法。有时它们是您可以提供的最佳界面。但是,在许多情况下却不是。在许多情况下,您只是将实现细节泄漏到其他类中。

–温斯顿·埃韦特(Winston Ewert)
2010-11-27 15:32

#12 楼

首先,我将对两种类型的对象进行评论,即值和服务类型。传递依赖关系的最佳方法是通过构造函数或工厂,这种方法从一开始就以简单明了的方式完全形成所有实例。

值类型也应该是不可变的,另一方面,有时这是不实际的,例如ORM或其他一些映射,例如从小部件到对象。在系统中从一层或一部分传递到另一层或另一部分的所有其他值类型应该是不可变的,并且不应具有setter。

评论


我建议使用第三种类型:可变容器,其目的是保存一个或多个值。在许多情况下,不应期望容器具有太多的逻辑或验证方式。需要一种用于计算六个正整数的方法的代码可以将六个整数的容器传递给将结果存储在其中的方法。确保数字为正的责任通常应由调用者或被调用方法承担,而不应由容器承担。

–超级猫
16年1月13日在22:37

#13 楼

Getter / Setter的合理性与其他任何公共方法的合理性一样。理由主要是因为我们要提供一个与外界的接口,以定义我们的类与其他类的交互方式。我们这样做主要是因为我们要减少单独实体之间的耦合。减少耦合是一件好事,原因有很多:


我可以在当前代码中使用相同的类接口,尽管与此同时该类添加了新方法(但保留了旧接口)
可以在不影响类使用者的情况下更改类的内部表示形式
减少错误的机会:如果将内部数据设为私有,则可以肯定地知道外部代码不会与您的内部数据混淆


#14 楼

是的,getter和setter是面向对象编程中的反模式,永远不应使用:http://www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html。简而言之,它们不适合面向对象的范例,因为它们鼓励您将对象视为数据结构。这是一个主要的误解。

评论


在先前的18个答案中,这似乎并没有提供任何实质性的解释。

– gna
2014-09-16 11:10



它也永远说不出来。

–温斯顿·埃韦特(Winston Ewert)
2014年9月16日14:59

#15 楼

我希望由开发您的编程语言的公司自动开发的IDE不会违反“对象定向原理”。

话虽如此,只要您有一个公共范围的变量,使用一个getter和一个setter,你就是金。在我看来,这是极其面向对象的封装原理的必要元素-即使它看起来像很多垃圾代码。

之所以要使用它们,是因为可能已经进行了适当的封装,并且只要您抽象出了一个可以使人随身携带的物体感觉到您的物体的层,就可以将其取走离开他甚至都不知道对不对?

可以这么说,一间分开的房子无法忍受,OO的一个租户不会自行打开,您不能同时进行封装和过早优化。

评论


每次处理变量时,通过添加大量代码来调用setFoo()和getFoo()到底能获得什么呢?

–温斯顿·埃韦特(Winston Ewert)
2010-11-26 23:29

这是东西,我不认为您会得到封装。您仍在从其他地方操纵对象的状态。您只是在做更冗长的操作。为了获得封装,您需要在拥有该值的类中集中对值进行操作。其他所有只是OO服装中的过程代码。 (这不一定是错的,但这就是事实)。

–温斯顿·埃韦特(Winston Ewert)
2010-11-26 23:58

封装的优点是,与特定值相关的所有逻辑都在一个地方(或多或少)。我不能通过getter和setter来理解。因此,我认为我没有为他们带来很多好处。

–温斯顿·埃韦特(Winston Ewert)
2010-11-26 23:59

但是,我同意,我宁愿使用getter和setter编写代码,然后使用通过公共访问自由操作数据的代码。这样,我至少可以附加对传入数据的验证。

–温斯顿·埃韦特(Winston Ewert)
2010-11-27 0:00
我当然不喜欢冗长。但是我的反对意见是真正的人,他们将变量设为私有,然后自由调用它们的getter和setter方法,最终几乎没有区别。如果您想在课堂上使用getter / setter,那很好。问题是为什么?我知道的主要好处是,您可以对数据进行一些验证以更早地捕获错误。当所有用于处理数据的代码都位于同一位置时,此方法的用处不大。但这仍然会有所帮助。理想情况下,您使用的语言应支持属性并且可以避免冗长。

–温斯顿·埃韦特(Winston Ewert)
10-11-27在1:12



#16 楼

我以为我们会在这里得到更多常见的答案?要记住不要过度设计工程师,切勿制造不需要的吸气剂或装料器。您不打算将其用于其他类的任何信息都不应具有任何getter或setter。主要是:


无法使用字段进行适当的测试。在这方面,getter / setter更好。
在实时编程设置中正确使用字段是不可能的。同步获取器/设置器是必经之路。
接口主题(已经说明,所以我不会)。
正确重用系统时使用起来更容易。哪些类正在使用您的类,并且如果您更改字段而不是获取/设置器,那将中断什么。进行一个官方项目,但只是为了好玩而已,并且不必理会getter / setter。

评论


+1可测性。震惊的是没有人提到它。属性的另一个有用功能是调试它们。 (比要求字段的硬件/内存断点更容易在代码中插入断点)。

– Mark H
2010-11-27 18:29

对吸气剂和吸气剂的异议是,它们经常被用来遵循OOP法律,而忽略了精神和意图。 OOP表示您不应该让其他物体与您的内部物体混在一起。如果您定义了无论如何都可以做到的getter和setter,那么最终将违反OOP。

–温斯顿·埃韦特(Winston Ewert)
10-11-27在19:23

我会同意,与简单的公共领域相比,getter和setter有很多好处。但是,我不清楚使用它们进行测试如何更好。你能解释一下吗?

–温斯顿·埃韦特(Winston Ewert)
10 Nov 27 '19:24

@Skarion:我不同意你的回答。您似乎提出了两种选择:使用getter / setter或公开字段。但是还有第三种选择:既不使用getters / setter方法,也不使用字段!为什么需要测试内部字段的状态?您不应该测试对象的公共API吗?

– Andres F.
2011年11月21日15:31