【问题标题】:Repeated setters logic in DelphiDelphi中的重复设置器逻辑
【发布时间】:2009-07-23 07:10:31
【问题描述】:

对于每个类的设置器,我必须实现一些事件逻辑(OnChanging、OnChanged):

procedure TBlock.SetWeightIn(const Value: Double);
var OldValue: Double;
begin
  OldValue := FWeightIn;
  DoOnChanging(OldValue, Value);
  FWeightIn := Value;
  DoOnChanged(OldValue, Value);
end;

procedure TBlock.SetWeightOut(const Value: Double);
var OldValue: Double;
begin
  OldValue := FWeightOut;
  DoOnChanging(OldValue, Value);
  FWeightOut := Value;
  DoOnChanged(OldValue, Value);
end;

您能否建议一种方法来实现这一点,而无需为每个 setter 复制所有这些行?

【问题讨论】:

  • +1 vor general 事件库编程中经常会遇到的问题。
  • 您应该首先检查 Value OldValue,它是整个 VCL 中使用的惯用语。在方法开始时,或者在 OnChanging 事件之后(取决于 OnChanging 是否获取 var 参数,即是否可以更改新值)。

标签: delphi pascal delphi-2006


【解决方案1】:

试试这个:

procedure TBlock.SetField(var Field: Double; const Value: Double);
var
    OldValue: Double;
begin
    OldValue := Field;
    DoOnChanging(OldValue, Value);
    Field := Value;
    DoOnChanged(OldValue, Value);
end;

procedure TBlock.SetWeightIn(const Value: Double);
begin
    SetField(FWeightIn, Value);
end;

procedure TBlock.SetWeightOut(const Value: Double);
begin
    SetField(FWeightOut, Value);
end;

【讨论】:

  • 实际上 - 这与我的解决方案相同,但语法更好。
  • 不仅仅是 更好 语法,Tobias。 有效语法。
  • 我打错了 - 我只是使用了类型而不是变量名。我更正了我的示例,我手头没有编译器。如您所见,这是一个有效的语法。这个想法保持不变。您传递地址(通过指针或使用 var)。编译器做同样的事情。在二进制级别上,结果是相同的——只是语法更好,正如我之前所说的。使用起来也不容易。
【解决方案2】:

Delphi 支持索引属性。多个属性可以共享一个 getter 或 setter,由序号索引区分:

type
  TWeightType = (wtIn, wtOut);
  TBlock = class
  private
    procedure SetWeight(Index: TWeightType; const Value: Double);
    function GetWeight(Index: TWeightType): Double;
  public
    property InWeight: Double index wtIn read GetWeight write SetWeight;
    property OutWeight: Double index wtOut read GetWeight write SetWeight;
  end;

您可以将其与Cobus's answer 结合以获得此:

procedure TBlock.SetWeight(Index: TWeightType; const Value: Double);
begin
  case Index of
    wtIn: SetField(FWeightIn, Value);
    wtOut: SetField(FWeightOut, Value);
  end;
end;

这可能会为您提供其他方法的想法,您可以通过索引引用字段,而不是为此类相关值使用两个完全独立的字段。

【讨论】:

  • +1 对于我几乎给出的答案,但认为它会太长。似乎它仍然可以紧凑地描述:-)
【解决方案3】:

您可以添加其他方法。比如:

procedure TBlock.setValue(const Value : Double; Location : PDouble);
var
  OldValue : Double;
begin
   OldValue:=Location^;
   DoOnChanging(OldValue,Value);
   Location^:=Value;
   DOnChanged(OldValue, Value);
end;

procedure TBlock.setWeightOut(const Value : Double);
begin
  setValue(value, @FWeightOut);
end;

不过,我还没有编译/测试过代码。这个想法是有一个通用的 setter 方法,它与指向该位置的指针一起工作。专用版本只是调用带有要设置的变量地址的通用方法。 但是,对于每种类型的变量(双精度型、整数型、...),您必须拥有一种通用的 setter 方法。您可以对其进行修改以处理指针和变量的长度以适用于所有类型 - 您的决定是否值得。

【讨论】:

  • 你应该使用 var 参数而不是指针,就像 Cobus Kruger 的建议一样。
  • @Tobias:不,不仅仅是语法糖。使用 var 参数不可能传递 NULL 指针,因此 SetValue() 方法不必检查(顺便说一句,您的代码不需要!)。滥用可能性较小的 API 会更好。
【解决方案4】:

如果过程/函数的参数相同并且开始和结束之间的代码相同,那么您可以使用

procedure SetWeightValue(const Value: Double);
var OldValue: Double;
begin
  OldValue := FWeightIn;
  DoOnChanging(OldValue, Value);
  FWeightIn := Value;
  DoOnChanged(OldValue, Value);
end;

就是这样……

【讨论】:

    猜你喜欢
    • 2013-11-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-03
    • 2012-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多