4

我目前正在重写一个免费的教育数字电路模拟器,以增加其特性的惯性。我的问题是如何将事件分派给原始类,为它们添加预详细说明。我有这样的事情:

TC1 = class
  ID: integer;
  Connections : array [integer] of Pin;
  function Func1; virtual;
  function FuncN;
end;

TC2-1 = class (TC1)
  function Func1; override;
  function My1Func();
end;

TC2-n = class (TC1)
  function Func1; override;
  function MyNFunc();
end;


TContainer = class
  C1 : TC1;
  function ContFunc;
end;

function Container.ContFunc;
begin
    c1.Func1;
end;

现在这意味着 ContFunc 如我所愿调用 C2.Func1,专门化 300 多个继承自 TC1 的组件的行为。

但是现在我必须添加一些特殊操作(每次调用 Func1 时,对于来自 TC1 的所有组件后代都相等,并且如果我必须调用 TC2-n.Func1 则在该操作期间进行选择(在更改祖先 TC1 的某些属性之后。是有没有办法在不改变 TC1 的所有后代的情况下干净地做到这一点?我可以像这样使用辅助类(不推荐使用吗?):

TH = class helper of TC1
  function Func1 virtual; override;
end;

function TH.Func1;
begin
  if x then TC2.Func1 else SaveActionData; 
end

如果我添加 TH,当 TContainer 调用 Func1 时,会调用谁?它像我希望的那样调用 TC2.Func1 而不是 TH.Func1?有没有一种方法可以覆盖后代方法 Func1 而无需为任何单个类编写辅助类(它们将执行所有相同的操作,意味着完全相同的代码)?可以从 TH 调用 TC2-n 的 300 个后代函数 Func1 吗?

换句话说,我试图找到一种方法来通过 Tcontainer 调用 c1.Func1; 来获得这样的调用:

调用 TC2.Func1 的 NewFunc1(对所有 TC1 后代均等)(对于 TC1 的任何后代均不同)。

任何人都可以提出一种方法来做到这一点?

4

3 回答 3

4

Func1无论后代在其覆盖的方法中选择做什么,您都有一些任务需要在有人调用时执行。这是模板方法模式的工作。

为基类提供一个公共的非虚拟方法,该方法Func1执行您需要的操作,然后调用受保护的虚拟方法。后代可以覆盖该虚拟方法,但使用该类的任何人都只能调用公共非虚拟方法。

type
  TC1 = class
  protected
    function InternalFunc1: Integer; virtual; // abstract?
  public
    function Func1: Integer;
  end;

function TC1.Func1;
begin
  if x then
    Result := InternalFunc1
  else
    Result := SaveActionData; 
end;

现在后代可以覆盖InternalFunc1,并且基类将确保仅在适当的时候调用它。

type
  TC2 = class(TC1)
  protected
    function InternalFunc1: Integer; override;
  end;

您需要Func1在所有 300 个后代类中重命名当前函数。IDE 的重构工具可能会对此有所帮助。

于 2010-03-02T16:42:24.483 回答
0

类助手对于修改您无法从源头获取的类很有用。如果您是 TC1 类的作者,并且可以通过为 TC1 引入类帮助器来进行必要的更改,那么为什么不直接修改 TC1.Func1,然后就完成了?那应该行得通。

于 2010-03-02T11:56:14.083 回答
0

您可以按照装饰器模式创建一个包装器类,以描述程序在模拟模式下运行时需要执行的特殊任务。它可以保存您的数字组件的一个实例,并在执行自己的任务后调用该组件的方法。

type
  TAnalogueDecorator = class(TC1)
  private
    FComponent: TC1;
  public
    constructor Create(Wrapped: TC1);
    destructor Destroy; override;

    function Func1: Integer; override;
  end;

constructor TAnalogueDecorator.Create(Wrapped: TC1);
begin
  inherited Create;
  FComponent := Wrapped;
end;

destructor TAnalogueDecorator.Destroy;
begin
  FComponent.Free;
  inherited;
end;

function TAnalogueDecorator.Func1: Integer;
begin
  SaveActionData;
  Result := FComponent.Func1;
end;

请注意,无需x事先检查您的状况。不必在每次调用任何方法时都检查它,而是可以在用模拟组件包装数字组件之前检查一次。现在,您最初直接在数字类上调用的所有地方都Func1首先绕过模拟类的方法。

于 2010-03-02T16:42:12.127 回答