Как инкапсулировать разные классы в одном классе, поддерживая их уникальные методы? (множественное наследование в Delphi?) - PullRequest
4 голосов
/ 02 марта 2010

В настоящее время я переписываю бесплатный обучающий симулятор цифровых схем, чтобы добавить инерционность его функциям. Моя проблема в том, как отправлять события в исходные классы, добавляя к ним предварительную разработку. У меня есть что-то вроде этого:

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.

Но теперь я должен добавить некоторые специальные операции (одинаковые для всех потомков компонентов). из TC1 каждый раз, когда вызывается Func1, и выбирая во время этих операций, если мне нужно вызывать 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 вызвать 300 потомков функций Func1 TC2-n?

Другими словами, я пытаюсь найти способ получить такой вызов с помощью вызова Tcontainer c1.Func1;:

NewFunc1 (равно для всех потомков TC1), которые вызывают TC2.Func1 (отличается для любого потомка TC1).

Кто-нибудь может предложить способ сделать это?

Ответы [ 3 ]

4 голосов
/ 02 марта 2010

У вас есть некоторые задачи, которые нужно выполнять всякий раз, когда кто-то вызывает Func1, независимо от того, что потомки решили делать в своих переопределенных методах. Это задание для шаблона с шаблоном pattern.

Предоставьте базовому классу открытый не виртуальный метод 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 могут помочь с этим.

0 голосов
/ 02 марта 2010

Вы можете создать класс-оболочку, следуя шаблону decorator , чтобы описать специальные задачи, которые должны выполняться, когда ваша программа работает в аналоговом режиме. Он может содержать экземпляр вашего цифрового компонента и вызывать методы этого компонента после выполнения своих собственных задач.

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 непосредственно в цифровом классе, вначале отклоняются от методов аналогового класса.

0 голосов
/ 02 марта 2010

Помощники классов полезны для изменения классов, к которым у вас нет доступа.Если вы являетесь автором класса TC1, и вы сможете внести необходимые изменения, введя вспомогательный класс для TC1, то почему бы просто не изменить TC1.Func1, и тогда все готово?Это должно работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...