Как реализовать одинаковые методы с 2 и более классами? - PullRequest
6 голосов
/ 10 января 2012

Я хочу написать потомков TCheckBox и TRadioButton, имеющих 3 одинаковых метода.

TMyCheckBox = class(TCheckBox)
  procedure DoSomething1;
  procedure DoSomething2;
  procedure WMSize(var Message: TWMSize); message WM_SIZE;
end;

TMyRadioButton = class(TRadioButton)
  procedure DoSomething1;
  procedure DoSomething2;
  procedure WMSize(var Message: TWMSize); message WM_SIZE;
end;

// the following procedures are common for both classes, so in fact
// TMyCheckBox.DoSomething1 do the same as TMyRadioButton.DoSomething1

procedure DoSomething1;
begin
  // here is the same code for TMyCheckBox as well as for TMyRadioButton
  // but I don't want to write the same code many times but implement it
  // for both classes at once in some common way
end;

procedure DoSomething2;
begin
  // here is the same code for TMyCheckBox as well as for TMyRadioButton
  // but I don't want to write the same code many times but implement it
  // for both classes at once in some common way
end;

procedure WMSize(var Message: TWMSize); message WM_SIZE;
begin
  // here is the same code for TMyCheckBox as well as for TMyRadioButton
  // but I don't want to write the same code many times but implement it
  // for both classes at once in some common way
end;

Как я могу это сделать?

Ответы [ 2 ]

11 голосов
/ 10 января 2012

Определите интерфейс, скажем IDoSomething с тремя сигнатурами метода.

Затем измените объявление класса на

TMyCheckBox = class(TCheckBox, IDoSomething)

, а затем реализовать.

Если реализации являются общими или очень близкими.

Затем определите вспомогательный класс TDoSomething и затем делегируйте работу.

, например

Procedure TMyCheckBox.DoSomething1; // implements IDoSomething1
Begin
  TDoSomething.DoSomething1(Self); // given class method will suffice.
End;

Методы класса в delphi, эквивалентные статическим методам в других языках.

Type
    TDoSomethingHelper = Class(TObject)
    Public
      Class Procedure DoSomething1(aComponent : TComponent);
    End;

...
implementation

Class Procedure TDoSomethingHelper.DoSomething1(aComponent : TComponent);
Begin
  aComponent.Tag = 27;
End;
8 голосов
/ 10 января 2012

Вы ищете наследование реализации, а не наследование интерфейса.Это возможно только в Delphi, если вы можете получить классы от одного общего предка.Это ограничение присуще, потому что язык поддерживает только одиночное наследование.

Лучшее, что вы можете сделать, это примерно так:

type
  TMyWinControlExtender = class
  private
    FTarget: TWinControl;
  public
    constructor Create(Target: TWinControl);
    procedure WMSize(var Message: TWMSize; out CallInherited: Boolean);
    procedure DoSomething;
  end;

  TMyCheckBox = class(TCheckBox)
  private
    FExtender: TMyWinControlExtender;
  protected
    procedure WMSize(var Message: TWMSize); message WM_SIZE;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure DoSomething;
  end;

  TMyRadioButton = class(TRadioButton)
  private
    FExtender: TMyWinControlExtender;
  protected
    procedure WMSize(var Message: TWMSize); message WM_SIZE;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure DoSomething;
  end;

{ TMyWinControlExtender }

constructor TMyWinControlExtender.Create(Target: TWinControl);
begin
  inherited Create;
  FTarget := Target;
end;

procedure TMyWinControlExtender.WMSize(var Message: TWMSize; out CallInherited: Boolean);
begin
  if FTarget.... then
    ....
  CallInherited := ...;
  //etc.
end;

procedure TMyWinControlExtender.DoSomething;
begin
  if FTarget.... then
    ....
  //etc.
end;

{ TMyCheckBox }

constructor TMyCheckBox.Create(AOwner: TComponent);
begin
  inherited;
  FExtender := TMyWinControlExtender.Create(Self);
end;

destructor TMyCheckBox.Destroy;
begin
  FExtender.Free;
  inherited;
end;

procedure TMyCheckBox.DoSomething;
begin
  FExtender.DoSomething;
end;

procedure TMyCheckBox.WMSize(var Message: TWMSize);
var
  CallInherited: Boolean;
begin
  FExtender.WMSize(Message, CallInherited);
  if CallInherited then
    inherited;
end;

И аналогично для TMyRadioButton и т. Д.1008 * Теперь вы можете использовать интерфейсы и делегирование, чтобы уменьшить часть шаблона, но для этого нет способа помочь с обработчиком сообщений, таким как WMSize.

...