OOP所有属性都应该有getter和setter

时间:2012-08-23 13:22:56

标签: oop design-patterns

我总是为大多数类属性提供getter和setter。

虽然我已经读到这很糟糕 - http://www.codeweavers.net/getters-and-setters-are-evil/

依赖注入和单元测试是否要求大多数属性都有一个setter?

4 个答案:

答案 0 :(得分:4)

应始终使用Getter和setter。 getter或setter的原因不是为内部属性提供公共接口,而是提供对属性读/写的控制。它们提供了类属性的抽象。

即使您的类属性是私有的,您也需要getter和setter。这允许在分配或读取之前控制值。

考虑一下你很久以前设计的课程,你会为每次阅读做一些常见的计算。

class A{
    private decimal x;
    public void do_stuff(){
        decimal a = this.x/70;
        // process with a
    }
    public void do_anoter_stuff(){
        decimal a = this.x/70;
        // process again a
    }
}

现在你想改变因子(70)。你怎么做呢?在每个地方改变它?更好地设计它。

class A{
    private decimal x;
    private get_x(){ return this.x/70; }
    public void do_stuff(){
        // process with get_x()
    }
    public void do_anoter_stuff(){
        // process again get_x()
    }
}

事实是盲目地使用吸气剂和每个财产的制定者是邪恶的。经验法则是。使用私有getter和setter将所有属性声明为私有。稍后更改getter和setter的可见性仅允许在需要时从外部世界进行访问

答案 1 :(得分:1)

该文章的内容是,您不应通过公共getter和setter公开您的私人数据。为所有成员设置getter和setter并不是一个错误的错误(有些人会认为这是一个好主意,虽然实际上很少有人真的为每个私人变量而烦恼...我还没有见过任何真正做过的人反正)

一个坏主意是为每个变量设置公共 getter和setter。这几乎可以保证封装不良的类。

在c ++中,有可能通过友谊绕过私人访问来提供白盒测试,我认为你可以使用其他语言的其他机制做同样的事情,但我不确定(我只是商业上开发的每一种)在c ++中,我不会测试我在Java和C#中编写的应用程序。可能反射将允许你正在寻找的行为。

答案 2 :(得分:1)

该文章所说的是OO意味着封装数据并提供行为。通过提供属性,您不会封装数据。例如,您可以像这样实现Account类:

public class Account
{
  public decimal Balance { get;set; }
}

但是,从概念上讲,这与:

没有什么不同
public class Account 
{
  public decimal Balance;
}

在任何一种情况下,该类都没有行为。在Account上运行的所有行为都必须在Account之外。文章所说的是行为和国家应该共同生活。所以,你可能会有这样的事情:

public class Account 
{
  private decimal balance;
  //...
  public void DepositFunds(Money money)
  {
    balance += ValidateAndConvert(money);
  }
  public void WithdrawFunds(Money money)
  {
    balance -= ValidateAndConvert(money);
  }
  public void AdjustBalance(Money money)
  {
    balance -= ValidateAndConvert(money);
  }
  private decimal ValidateAndConvert(Money money)
  {
    // TODO: validate, convert
  }
}

如果帐户具有作为属性或字段的余额,则外部逻辑可以根据需要对其进行修改。这通常会在整个代码库中分散业务逻辑。如果需要从账户中提取资金的逻辑来检查余额并验证账户不能透支,或者只是透支了一定金额,那么代码中的许多地方都必须提供该逻辑。如果需要改变许多地方的逻辑必须被发现和改变(风险是一个被错过并且出现不一致的撤销)。当数据封装在对象中并且仅提供行为时,该逻辑无法分散在代码库中。这也允许更明确的代码。可能是account.Balance -= someValue;可能是撤回,调整等等。现在它可以是明确的:account.Widthdraw(someValue);或account.AdjustBalance(someOtherValue);` - 明确帐户发生了什么

答案 3 :(得分:-1)

除非您需要,否则我不会添加getter / setter,否则很难知道在需要进行更改时其他类所依赖的数据/方法。此外,过度使用getter / setter可能是面向对象设计不佳的一个症状,这些都是关于数据封装的。

Getters当然可以帮助基于状态的单元测试,尽管您可以考虑限制范围,以便只有测试类可以访问它们。或者甚至更好,通过创建equals方法在类本身中进行相等性检查。

依赖注入有助于避免使用getter,因为您可以通过注入模拟对象来执行interaction-based testing