9

哪个更好 ???

public class Order
{
   private double _price;
   private double _quantity;

  public double TotalCash
  {      
   get
   {
    return _price * _quantity;
   }
}

或者

public class Order
{

   private double _totalCash;
   private double _price;
   private double _quantity;

  private void CalcCashTotal()
 {
   _totalCash = _price * _quantity
 }

  public double Price
  {      
   set
   {
     _price = value;
     CalcCashTotal();
   }
  }

  public double Quantity
  {      
   set
   {
     _price = value;
     CalcCashTotal();
   }
  }


  public double TotalCash
  {      
   get
   {
    return _totalCash;
   }
}
4

13 回答 13

14

有权衡。如果计算简单并且不需要很长时间,那么就把它放在get中。它使您的生活更轻松,因为您不必担心在总价所依赖的每一组中都进行检查,这可能会导致错误。

如果计算需要很长时间,那么您也可以采用混合方法。您可以在所有依赖集中设置一个 IsDirtyTotalPrice 布尔值,然后在 get 中即时进行计算并将其缓存,以便 get 仅在需要时计算变量。您不会在集合中进行计算,因为它们可能很多,并且您希望尽可能少地进行计算。

  public class Order
  {
     private double _totalCash;
     private double _price;
     private double _quantity;
     private _IsDirtyTotalCash = true;

  private void CalcCashTotal()
  {
    _totalCash = _price * _quantity
  }

  public double Price
  {      
   set
   {
     _price = value;
     _IsDirtyTotalCash = true;
   }
  }

  public double Quantity
  {      
   set
   {
     _price = value;
     _IsDirtyTotalCash = true;
   }
  }

  public double TotalCash
  {      
   get
   {
        if(_IsDirtyTotalCash)
    {
      _totalCash = CalcTotalCost();
       _isDirtyTotalCash = false;
     }
     return _totalCash;
   }
  }

}
于 2009-01-15T05:16:50.617 回答
4

通常我会尝试将它们放在场景中,因为它们生成的值将存储在内部并且只需要计算一次。只有在每次查询时值都可能发生变化时,才应该在 get 上进行计算。

在您的价格/数量示例中,您实际上可以有一个单独的方法,在设置价格或数量时重新计算数量。

于 2009-01-15T04:59:58.187 回答
3

第一个更好,因为:

  • 它更短。
  • 更容易理解。
  • 每次设置价格或数量时重新计算 TotalCash 有点冒昧。它应该尽可能地懒惰,并且只在请求时计算。

话虽如此,将计算放在 setter 中有效地缓存了它,因此如果遇到性能问题,这可能是一个有用的更改(以清晰度为代价)。

于 2009-01-15T05:02:04.733 回答
3

我会接受查尔斯格雷厄姆的混合建议,但我想加上我的两分钱来解释为什么。

上面的很多建议都谈到了复杂性和优化,但是当你考虑到你的类的消费者时,忘了这一切都消失了。如果是唯一的消费者,并且您使用了第一个实现,那么您很可能会记得:

double subTotal = myOrder.TotalCash;
double tax = subTotal * 0.05;
double shipping = subTotal > 100 ? 0 : 5.95;
double grandTotal = subTotal + tax + shipping;
OutputToUser(subTotal, tax, shipping, grandTotal);

其他人可能不会。看到这myOrder.TotalCash是一个属性,而不是一个方法,至少我会假设它是一个缓存值。也就是说,subTotal上例中的访问在效率上与访问相当myOrder.TotalCash。他们没有意识到幕后正在进行计算,他们写道:

double tax = myOrder.TotalCash * 0.05;
double shipping = myOrder.TotalCash > 100 ? 0 : 5.95;
double grandTotal = myOrder.TotalCash + tax + shipping;
OutputToUser(myOrder.TotalCash, tax, shipping, grandTotal);

离开myOrder.TotalCash代表小计。现在,它已经计算了 4 次而不是 1 次。

总而言之,我确信我不是唯一一个相信属性表示变量或缓存值并且方法处理某些内容并返回值的人。存储并且只调用一次是有意义的CalculateTotalCash(),因为您希望它会成为性能冲击。另一方面,您期望TotalCash成为一个缓存值并且可以随意访问它。因此,重要的是仅TotalCash在它发生变化时重新计算。

在读取之间有多个集合的情况下,混合建议获胜。这样,您就不会浪费时间计算要丢弃的值。

于 2009-01-15T05:59:32.120 回答
3

在确定是否应派生/计算属性时,重要的是要考虑计算时的值是否需要保留。

在 TotalCash 的这种情况下 - 如果计算的业务逻辑发生更改,则可能不希望对现有记录追溯更改 TotalCash 属性。

只是把它放在那里...

于 2009-01-15T05:59:35.913 回答
2

第一个,因为:
1)代码越少越好;
2)复杂度低;
3)更少的变量有助于减少附带问题;
4) 属性会一直更新;
5)如果您更改“CalcCashTotal”程序名称,您将获得更多其他点来更改...

于 2009-01-15T05:09:11.507 回答
1

放在get函数上不是很理想。您将无缘无故地重新计算它。它甚至没有任何意义。所以这里是 ::gasp:: 优化有意义并且是首选的情况。计算一次并获得收益。

于 2009-01-15T05:10:23.750 回答
1

我一直被告知,如果有大量的工作或计算正在进行,你应该用一种方法来做。据我所知,没有主要的编译器/运行时优势,但它对代码的使用者来说更有意义。需要一段时间才能将值返回给我的属性会引发一个危险信号,表明可能有问题。

那是我的 2 美分……但如果课程真的那么简单,我可能也会选择你的第一个例子:-)

于 2009-01-15T05:18:26.103 回答
1

第一个选项更好。“优化”的差异是微乎其微的。更不用说,如果设置一遍又一遍,但您只需要获取一次 TotalCost 怎么办?一旦课程变得非常复杂,我会更担心失去开发人员尝试调试课程的时间。

但是有一个重要的时候需要第二个选项,特别是当计算值改变计算对象时。我很难想出一个例子,所以我将使用一个真实的例子,其中墙壁中的隔间数量由其宽度决定。

class Wall {
    public decimal Width {
       get {
           ...
       }
       set {
           ValidateChanges();
           width = value;
           CreateBays();
       }
    }

    public Bays[] Bays {
       get {
           ...
       }
       set {
           ValidateChanges();
           ...
       }
    }

    private void CreateBays() {
        // Delete all the old bays.
        ...
        // Create a new bay per spacing interval given the wall width.
        ...
    }
}

在这里,每次宽度变化时,都会重新创建墙上的隔间。如果这发生在 Bay.getter 上,那么 Bay 对象的属性将是相当灾难性的。getter 必须弄清楚自上次 get 语句以来宽度是否发生了变化,从而增加了复杂性

于 2009-01-15T05:19:29.003 回答
1

这取决于。您的应用程序是读取繁重还是写入繁重?计算成本高吗?如果计算很昂贵并且您的应用程序读取量很大,请在片场进行,这样您只需支付几次计算惩罚(与读取相比)。

于 2009-08-24T03:51:50.223 回答
0

我将对只读 get 或 set 进行计算。

我认为一个属性应该表现得像它有一个支持变量。

我不喜欢需要很长时间读取的计算。

于 2009-01-15T04:59:21.400 回答
0

我会采用在 TotalCash 的 getter 中进行计算的方法,因为更少的代码几乎总是更好。它还确保 TotalCash 的值始终正确。作为一个人为的示例,如果您有另一个方法 NewOrder(Price, Qty) 并且您忘记在此方法结束时调用 CalculateTotal,您很容易以错误的 TotalCash 值结束。

如果计算需要一些时间来处理并且只更改一个或两个属性的值需要重新计算,那么在 setter 中计算它可能会更好,但几乎总是最好选择留下更少错误空间的方法,即使它执行时间稍长。

于 2009-01-15T05:03:04.933 回答
0

我的规则,我向任何人推荐这个:

方法 = 有副作用 Getters = 没有副作用(除了记忆 - 在 getter 中也是允许的)

于 2010-07-06T09:58:09.073 回答