你把计算放在你的集合或你的得分上吗?

时间:2009-01-15 04:55:51

标签: c# language-agnostic class methods oop

哪个更好???

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;
   }
}

13 个答案:

答案 0 :(得分: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;
   }
  }

}

答案 1 :(得分:4)

通常我会尝试将它们设置为set,因为它们生成的值将在内部存储,只需要计算一次。如果值在每次查询时都可能发生变化,您应该只计算get。

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

答案 2 :(得分:3)

第一个更好,因为:

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

话虽如此,将计算放入setter会有效地缓存它,所以如果遇到性能问题,那可能是一个有用的改变(以清晰度为代价)。

答案 3 :(得分: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发生变化时重新计算。

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

答案 4 :(得分:3)

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

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

把它放在那里......

答案 5 :(得分:2)

第一,因为:
1)更少的代码更好;
2)复杂性较低;
3)较少的变量有助于减少相关问题; 4)物业将始终更新;
5)如果您更改“CalcCashTotal”程序名称,您将获得更多要更改的点......

答案 6 :(得分:1)

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

答案 7 :(得分:1)

我一直被告知,如果有大量的工作或计算,你应该用一种方法来做。据我所知,没有主要的编译器/运行时优势,但它对代码的消费者更有意义。需要一段时间才能将值返回给我的属性会抛出一个可能出错的红旗。

这是我的2美分......但即使我的第一个例子,如果课程真的那么简单,我也可能会这样做: - )

答案 8 :(得分: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必须确定宽度是否已更改,增加复杂性

答案 9 :(得分:1)

这取决于。您的应用程序是重读还是重写?计算费用高吗? 如果计算费用昂贵并且您的应用程序读得很重,那就在集合上执行,这样您只需支付几次计算惩罚(与读取相比)。

答案 10 :(得分:0)

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

我认为一个属性的行为应该像它有一个支持变量。

我不喜欢长时间阅读的计算。

答案 11 :(得分:0)

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

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

答案 12 :(得分:0)

我的规则,我建议任何人:

方法=有副作用 吸气剂=没有副作用(除了记忆 - 这也是吸气剂中允许的)