Ответ 1
Delphi не поддерживает множественное наследование. Но классы могут поддерживать/реализовывать несколько интерфейсов, и вы можете делегировать реализацию интерфейса, чтобы вы могли моделировать множественное наследование.
Я полностью переписываю старую библиотеку, и я не уверен, как справиться с этой ситуацией (ради понимания, все приветствуют аналогию с байками):
У меня есть следующие классы:
TBike
- сам байкTBikeWheel
- одно из велосипедных колесTBikeWheelFront
и TBikeWheelBack
, оба наследуются от TBikeWheel
, а затем реализуют конкретные вещи, которые им нужны поверхЭто довольно просто, но теперь я решил создать несколько видов велосипедов, каждый из которых имеет свои собственные колеса - они делают то же самое, что и обычные передние/задние колеса, а также специальные для этого велосипеда.
TBikeXYZ
- наследует от TBike
TBikeWheelXYZ
- наследует от TBikeWheel
И вот моя проблема: TBikeWheelFrontXYZ
должен наследовать от TBikeWheelXYZ
(для получения конкретных методов колеса XYZ), но он также должен унаследовать от TBikeWheelFront
(чтобы получить конкретные методы переднего колеса).
Мой вопрос здесь в том, как я могу реализовать это так, как это не делает:
Delphi не поддерживает множественное наследование. Но классы могут поддерживать/реализовывать несколько интерфейсов, и вы можете делегировать реализацию интерфейса, чтобы вы могли моделировать множественное наследование.
Использовать интерфейсы. Что-то вроде этого (Сверху моей головы, на основе вашего описания.....)
type
IBikeWheel = interface
...
end;
IXYZ = interface
...
end;
IFrontWheel = interface(IBikeWheel)
...
end;
TBike = class
...
end;
TBikeWheel = class(TObject, IBikeWheel);
TBikeWheelXYZ = class(TBikeWheel, IXYZ);
TBikeFrontWheelXYZ = class(TBikeWheelXYZ, IFrontWheel);
Затем реализуйте классы для интерфейсов, которые выполняют соответствующие классы в вашей старой (предположительно, C/С++) библиотеке и создают их в соответствующем конструкторе классов.
Использовать полиморфизм для имплантирования каждой "вещи" как собственной иерархии объектов, а затем в свою очередь добавлять свойства объекта к этому объекту. Итак, создайте иерархию колес и иерархию велосипедов. Затем добавьте колеса в байки как поля в объекте велосипеда предка. См. Ниже.
TBikeWheel = class
TBikeWheelXYZ = class( TBikeWheel )
TBike = class
FFrontWheel : TBikeWheel;
property FrontWheel : TBikeWheel
read FrontWhell
TBikeABC = class( TBike)
constructor Create;
end;
constructor TBikeABC.Create;
begin
inherited;
FFrontWheel := TBikeWheel.Create;
end;
TBikeXYZ = class( TBike)
constructor Create;
end;
constructor TBikeXYZ.Create;
begin
inherited;
FFrontWheel := TBikeWheelXYZ.Create;
end;
В принципе - вы НЕ МОЖЕТЕ. Delphi не поддерживает множественное наследование.
Таким образом, с этой дилеммой возникает вопрос: не могли бы вы реорганизовать эту библиотеку таким образом, чтобы вы могли избежать использования интерфейса? Является ли множественное наследование в основном функциями и методами? Если используются так называемые интерфейсы. Delphi может поддерживать несколько интерфейсов в классе.
Если многонаследование больше связано с наследованием фактической функциональности в классах, то, вероятно, вы, вероятно, смотрите на рефакторинг большего масштаба. Вам нужно найти способ разбить эти функциональные зависимости таким образом, чтобы вы могли наследовать его из одного базового класса, возможно, с добавлением некоторых дополнительных интерфейсов.
Извините, я не могу дать простой ответ - это просто реальность.
Марк
Вы можете попытаться извлечь интерфейс, например, IFrontWheel, из TBikeWheelFront, так что это подкласс TBikeWheel, но реализует IFrontWheel. Затем TBikeWheelXYZ наследуется от TBikeWheel и TBikeWheelFrontXYZ наследует от TBikeWheelXYZ и реализует IFrontWheel.
Затем вы можете определить класс TFrontwheel и дать ему те же методы, что и интерфейс, но теперь вы их реализуете. Затем TBikeWheelFront и TBikeWheelXYZ получают частный член типа TFrontwheel и реализации IFrontWheel из них просто делегируют частные методы-члены.
Таким образом, у вас нет двойных реализаций.
Вариант предложения Брайана Фроста:
TBikeWheel = class
TBikeWheelXYZ = class( TBikeWheel )
TBike = class
FFrontWheel : TBikeWheel;
protected
function CreateWheel: TBikeWheel; virtual;
public
property FrontWheel : TBikeWheel
read FrontWheel
end;
TBikeABC = class( TBike)
protected
function CreateWheel: TBikeWheel; override;
end;
function TBikeABC.CreateWheel: TBikeWheel;
begin
result := TBikeWheel.Create;
end;
TBikeXYZ = class( TBike)
protected
function CreateWheel: TBikeWheel; override;
end;
function TBikeXYZ.CreateWheel: TBikeWheel;
begin
result := TBikeWheelXYZ.Create;
end;
Другой альтернативой новым версиям Delphi является использование дженериков в композиционной модели. Это особенно полезно в случае, когда несколько базовых классов (TBarA
и TBarB
в этом примере) недоступны для модификации (то есть: рамки или классы библиотеки). Например (примечание, для <краткости > здесь опущен необходимый destructor
in TFoo<T>
):
program Project1;
uses SysUtils;
{$APPTYPE CONSOLE}
type
TFooAncestor = class
procedure HiThere; virtual; abstract;
end;
TBarA = class(TFooAncestor)
procedure HiThere; override;
end;
TBarB = class(TFooAncestor)
procedure HiThere; override;
end;
TFoo<T: TFooAncestor, constructor> = class
private
FFooAncestor: T;
public
constructor Create;
property SomeBar : T read FFooAncestor write FFooAncestor;
end;
procedure TBarA.HiThere;
begin
WriteLn('Hi from A');
end;
procedure TBarB.HiThere;
begin
WriteLn('Hi from B');
end;
constructor TFoo<T>.Create;
begin
inherited;
FFooAncestor := T.Create;
end;
var
FooA : TFoo<TBarA>;
FooB : TFoo<TBarB>;
begin
FooA := TFoo<TBarA>.Create;
FooB := TFoo<TBarB>.Create;
FooA.SomeBar.HiThere;
FooB.SomeBar.HiThere;
ReadLn;
end.
вы можете попробовать таким образом, если вы не хотите повторять код несколько раз и хотите развязать код.
type
TForm1 = class(TForm)
btnTest: TButton;
procedure btnTestClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TBike = class
end;
IBikeWheel = interface
procedure DoBikeWheel;
end;
TBikeWheel = class(TInterfacedObject, IBikeWheel)
public
procedure DoBikeWheel;
end;
IBikeWheelFront = interface
procedure DoBikeWheelFront;
end;
TBikeWheelFront = class(TInterfacedObject, IBikeWheelFront)
public
procedure DoBikeWheelFront;
end;
IBikeWheelBack = interface
end;
TBikeWheelBack = class(TInterfacedObject, IBikeWheelBack)
end;
TBikeWheelFrontXYZ = class(TInterfacedObject, IBikeWheel, IBikeWheelFront)
private
FIBikeWheel: IBikeWheel;
FBikeWheelFront: IBikeWheelFront;
public
constructor Create();
property BikeWheel: IBikeWheel read FIBikeWheel implements IBikeWheel;
property BikeWheelFront: IBikeWheelFront read FBikeWheelFront implements IBikeWheelFront;
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
{ TBikeWheel }
procedure TBikeWheel.DoBikeWheel;
begin
ShowMessage('TBikeWheel.DoBikeWheel');
end;
{ TBikeWheelFrontXYZ }
constructor TBikeWheelFrontXYZ.Create;
begin
inherited Create;
Self.FIBikeWheel := TBikeWheel.Create;
Self.FBikeWheelFront := TBikeWheelFront.Create;
end;
{ TBikeWheelFront }
procedure TBikeWheelFront.DoBikeWheelFront;
begin
ShowMessage('TBikeWheelFront.DoBikeWheelFront');
end;
procedure TForm1.btnTestClick(Sender: TObject);
var
bikeWhell: TBikeWheelFrontXYZ;
begin
bikeWhell := nil;
try
try
bikeWhell := TBikeWheelFrontXYZ.Create;
IBikeWheelFront(bikeWhell).DoBikeWheelFront;
IBikeWheel(bikeWhell).DoBikeWheel;
except
on E: Exception do
begin
raise;
end;
end;
finally
if Assigned(bikeWhell) then FreeAndNil(bikeWhell);
end;
end;
Извините, Delphi не поддерживает множественное наследование.