【问题标题】:How to implement multiple inheritance in delphi?delphi如何实现多重继承?
【发布时间】:2009-08-14 05:18:23
【问题描述】:
我正在对一个旧库进行全面重写,但我不确定如何处理这种情况(为了便于理解,大家都欢迎自行车类比):
我有以下课程:
-
TBike - 自行车本身
-
TBikeWheel - 自行车的轮子之一
-
TBikeWheelFront 和 TBikeWheelBack,都继承自 TBikeWheel,然后在其之上实现他们需要的特定内容
这很简单,但现在我决定创建多种自行车,每辆自行车都有自己的车轮 - 它们与普通的前/后轮做相同的事情,加上针对该自行车的特定功能。
-
TBikeXYZ - 继承自 TBike
-
TBikeWheelXYZ - 继承自 TBikeWheel
这是我的问题:TBikeWheelFrontXYZ 应该继承自 TBikeWheelXYZ(获取 XYZ 轮的具体方法),但它也应该继承自 TBikeWheelFront(获取前轮的具体方法) .
我的问题是,我怎样才能以一种不这样的方式实现它:
- 感觉像个黑客
- 强迫我多次重写相同的代码
【问题讨论】:
标签:
delphi
multiple-inheritance
【解决方案1】:
Delphi 不支持多重继承。但是类可以支持/实现多个接口,你可以委托接口实现,所以你可以模拟多重继承。
【解决方案2】:
使用接口。像这样的东西(根据你的描述,在我的脑海中......)
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++)库中的相应类所做的接口实现类,并在相应类的构造函数中实例化它们。
【解决方案3】:
使用多态将每个“事物”实现为自身的对象层次结构,然后依次将对象属性添加到该对象。因此,创建一个车轮层次结构和一个自行车层次结构。然后将轮子添加到自行车作为祖先自行车对象中的字段。见下文。
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;
【解决方案4】:
Brian Frost 建议的变体:
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;
【解决方案5】:
基本上 - 你不能。 Delphi 不支持多重继承。
所以离开这个困境,问题是:你能不能重构那个库,让你可以摆脱使用接口的方式?多重继承主要是关于函数和方法吗?如果是这样 - 使用接口。 Delphi 可以在一个类上支持多个接口。
如果多重继承更多的是继承类中的实际功能,那么恐怕您正在考虑进行更大规模的重构。您需要找到一种方法来分解这些功能依赖关系,使其可以从单个基类继承,可能还会引入一些额外的接口。
抱歉,我无法提供简单的答案 - 这就是现实。
马克
【解决方案6】:
您可以尝试从 TBikeWheelFront 中提取一个接口,例如 IFrontWheel,使其成为 TBikeWheel 的子类,但实现了 IFrontWheel。然后 TBikeWheelXYZ 继承自 TBikeWheel 和 TBikeWheelFrontXYZ 继承自 TBikeWheelXYZ 并实现 IFrontWheel。
然后您可以定义一个类 TFrontwheel 并为其提供与接口相同的方法,但现在您实现它们。然后 TBikeWheelFront 和 TBikeWheelXYZ 得到一个 TFrontwheel 类型的私有成员,它们的 IFrontWheel 实现简单地委托给私有成员方法。
这样你就没有双重实现了。
【解决方案7】:
较新版本的 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.
【解决方案8】:
如果不想多次重复代码,想要解耦代码,可以试试这种方式。
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;
【解决方案10】:
我想建议以下步骤:
-
从TBikeWheelXYZ 或TBikeWheelFront 继承TBikeWheelFrontXYZ 类(因为在Delphi 中多重继承是不可能的,如上面的答案所述)。
-
将TBikeWheelXYZ 或TBikeWheelFront 的父类之一转换为TBikeWheel 类的类助手。
-
将类助手单元添加到声明TBikeWheelFrontXYZ 类的单元中。