如何设计小型的基于getter的类而不需要多次执行

本文关键字:不需要 执行 getter 小型 | 更新日期: 2023-09-27 18:13:23

我喜欢写很多小的getter属性,准确地描述它们的含义。

然而,这会导致重复的、昂贵的计算。

我所知道的所有避免这种情况的方法都会使代码的可读性降低。

伪代码示例:

ctor(decimal grossAmount, taxRateCalculator, itemCategory)
{
   // store the ctor args as member variables
}
public decimal GrossAmount { get { return _grossAmount, } }
private decimal TaxRate { get { return _taxRateCalculater.GetTaxRateFor(_itemCategory); } } // expensive calculation
public decimal TaxAmount { get { return GrossAmount * TaxRate; } }
public decimal NetAmount { get { return GrossAmount - TaxAmount; } }

在这个例子中,每个属性的作用非常明显,因为它们是简单的访问器。TaxRate已经被重构到它自己的属性中,所以它的作用也是显而易见的。如果_taxRateCalculator操作非常昂贵,如何避免重复执行而不破坏代码?

在我的实际场景中,我可能有10个需要这样处理的字段,所以10组_backing或Lazy字段会很难看。

如何设计小型的基于getter的类而不需要多次执行

缓存值

private decimal? _taxRate = null;
...
private decimal TaxRate
{
    get
    {
        if (!this._taxRate.HasValue) {
           this._taxRate = _taxRateCalculator.GetTaxRateFor(_itemCategory);
        }
        return this._taxRate.Value;
    }
}

你可以创建一个方法,每次调用它都会重新计算你的值。

这个解决方案的优点是

  • 你可以手动重新计算属性
  • 你可以实现某种Eventlistner,它可以在任何事情发生时轻松调用你的重新计算

.

  ctor(decimal grossAmount, taxRateCalculator, itemCategory)
    {
      // store the ctor args as member variables
      recalculate();
    }
    public decimal GrossAmount { get; private set; }
    public decimal TaxAmount { get; private set; }
    public decimal NetAmount { get; private set; }
    public void recalculate();
    {
       // expensive calculation
       var _taxRate = _taxRateCalculater.GetTaxRateFor(_itemCategory);
       GrossAmount = grossAmount;
       TaxAmount = GrossAmount * _taxRate ;
       NetAmount = GrossAmount - _taxRate;
    }

Profile。找出应用程序在哪些地方花费了大部分时间,这样就可以找到需要改进的地方。关注最严重的问题,除非对用户体验有重大影响,否则性能优化是没有意义的。

当您确定热点时,您需要做出决策-优化是否值得花费成本?如果是,请继续。使用后备字段来存储昂贵的计算是避免重复昂贵计算的标准方法。只是要确保只在重要的地方应用它,以保持代码的简单。

这真的是一个常见的做法,只要你确保你是一致的(例如,如果一些变化可能会改变税率,你想要无效的存储值,以确保它得到重新计算),你将会很好。只要确保您正在修复一个真正的性能问题,而不是仅仅追求一些性能理想=)

我认为没有办法。您希望缓存数据而不需要缓存。您可以在GetTaxRateFor(…)方法中构建缓存功能,但我怀疑这是您调用的唯一昂贵的方法。

所以最短的方法是BackingField。我通常是这样做的:

private decimal? _backingField;
public decimal Property { get { return _backingField ?? (_backingField = expensiveMethode()).Value; } }