3

我一直为大多数类属性提供 getter 和 setter。

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

依赖注入和单元测试不要求大多数属性都有一个设置器吗?

4

4 回答 4

5

应始终使用 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 将所有属性声明为私有。稍后更改 getter 和 setter 的可见性,仅在需要时允许从外部世界访问

于 2012-08-23T13:34:16.543 回答
1

那篇文章的意思是,您不应该通过公共 getter 和 setter 公开您的私人数据。为所有成员设置 getter 和 setter 并没有隐含的错误(有些人会争辩说这是一个好主意,尽管实际上很少有人真正为每个私有变量而烦恼……我还没有遇到真正这样做的人反正)

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

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

于 2012-08-23T13:37:05.320 回答
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);`--这是明确的帐户发生了什么。

于 2012-08-24T00:02:29.643 回答
-1

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

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

依赖注入可以帮助您避免 getter,因为您可以通过注入模拟对象来进行基于交互的测试。

于 2012-08-23T13:32:18.540 回答