2009-08-14 1 views
12

Я делаю полную перезапись старой библиотеки, и я не знаю, как справиться с этой ситуацией (ради того, чтобы быть поняты, все градом велосипед аналогии):Как реализовать множественное наследование в delphi?

У меня есть следующие классы:

  • TBike - велосипед сам
  • TBikeWheel - один из колеса велосипеда
  • TBikeWheelFront и TBikeWheelBack, как наследуется от TBikeWheel, а затем реализует конкретные вещи, они должны на нем

Это довольно просто, но теперь я решаю создать несколько видов велосипедов, каждый из которых имеет свои собственные колеса - они делают то же самое, что и обычные передние/задние колеса, а также специальные для этого велосипеда ,

  • TBikeXYZ - наследует от TBike
  • TBikeWheelXYZ - наследует от TBikeWheel

А вот моя проблема: TBikeWheelFrontXYZ должен наследоваться от TBikeWheelXYZ (чтобы получить конкретные методы в колеса XYZ), но должен также наследовать от TBikeWheelFront (для получения конкретных методов переднего колеса).

Мой вопрос здесь, как я могу осуществить это таким образом, что это не так:

  1. чувствовать себя как взломать
  2. сила меня переписать тот же код несколько раз

ответ

16

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

3

В принципе - вы НЕ МОЖЕТЕ. Delphi не поддерживает множественное наследование.

Таким образом, с этой дилеммой возникает вопрос: не могли бы вы реорганизовать эту библиотеку таким образом, чтобы вы могли избежать использования интерфейса? Является ли множественное наследование в основном функциями и методами? Если используются так называемые интерфейсы. Delphi может поддерживать несколько интерфейсов в классе.

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

Извините, я не могу предоставить простой ответ - это просто реальность.

Marc

2

Вы можете попытаться извлечь интерфейс, скажем, IFrontWheel, из TBikeWheelFront, так что это подкласс TBikeWheel, но реализует IFrontWheel. Затем TBikeWheelXYZ наследуется от TBikeWheel и TBikeWheelFrontXYZ наследует от TBikeWheelXYZ и реализует IFrontWheel.

Затем вы можете определить класс TFrontwheel и дать ему те же методы, что и интерфейс, но теперь вы их реализуете. Затем TBikeWheelFront и TBikeWheelXYZ получают частный член типа TFrontwheel, а реализация IFrontWheel из них просто делегирует частные методы-члены.

Таким образом, у вас нет двойных реализаций.

13

Использовать интерфейсы. Что-то вроде этого (Off верхней части моей головы, на основании вашего описания .....)

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/C++) библиотеки и создает их в конструкторе соответствующего класса.

4

Используйте полиморфизм для имплантации каждой «вещи» как самостоятельной иерархии объектов, а затем в свою очередь добавьте свойства объекта к этому объекту. Итак, создайте иерархию колес и иерархию велосипедов. Затем добавьте колеса в байки как поля в объекте велосипеда предка. Смотри ниже.

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; 
+0

+1, сдерживание часто моделирует реальность намного лучше, чем наследование. – mghie

1

Разновидность внушения Брайана Фроста:

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; 
1

Другая альтернатива с более новыми версиями Delphi является использование генериков в композиционной модели. Это особенно полезно в случае, когда множественные базовые классы (TBarA и TBarB в этом примере) недоступны для модификации (то есть: рамки или классы библиотеки). Например (примечание, в TFoo<T> необходимой destructor опущено здесь для краткости):

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. 
0

вы можете попробовать этот способ, если вы не хотите повторять код несколько раз и хотите развязан код.

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; 
0

Извините, Delphi не поддерживает множественное наследование.