11.2.3 多个接口与方法别名
接口的另一个非常重要的特点是一个类可以实现多个接口。下面的 TAthlete 类就演示了这一点,该类同时实现了 IWalker 和 IJumper 接口:
TAthlete = class(TInterfacedObject, IWalker, IJumper)
privateFJumpImpl: TJumperImpl;
publicconstructor Create;destructor Destroy; override;function Run: string; virtual;function Walk1: string; virtual;function IWalker.Walk = Walk1;procedure SetPos(Value: Integer);function GetPos: Integer;property Jumper: TJumperImpl read FJumpImpl implements IJumper;
end;
其中一个接口是直接实现的,而另一个接口则委托给了内部的 FJumpImpl 对象,就像我在上一个示例中所做的那样。
现在我们遇到了一个问题。我们要实现的两个接口都有一个具有相同签名的 Walk 方法,那么我们如何在类中同时实现这两个方法呢?在多个接口的情况下,Object Pascal语言如何支持方法名称冲突呢?解决的办法是给方法起一个不同的名字,并将其作为前缀映射到特定的接口方法,语句如下:
function IWalker.Walk = Walk1;
该声明表明,该类使用名为 Walk1 的方法来实现 IWalker 接口的 Walk 方法(而不是使用同名的方法)。最后,在实现该类的所有方法时,我们需要引用 FJumpImpl 内部对象的 Position 属性。
如果为 Position 属性声明一个新的实现,我们就会为一个运动员设置两个位置,这是一种相当奇怪的情况。下面是几个示例:
function TAthlete.GetPos: Integer;
beginResult := FJumpImpl.Position;
end;function TAthlete.Run: string;
beginFJumpImpl.Position := FJumpImpl.Position + 2;Result := IntToStr(FJumpImpl.Position) + ': Run';
end;
我们如何才能为 TAthlete 对象创建一个接口,并在 IWalker 和 IJumper 接口中引用这两种操作呢?事实上,我们不能这么做,因为我们没有一个可以使用的基础接口。不过,接口允许更动态的类型检查和类型转换,因此我们可以将一个接口转换为另一个接口,只要我们引用的对象支持这两个接口即可,编译器只能在运行时才能发现这一点。这就是这种情况下的代码:
当然,我们也可以从两个接口中任选一个,然后将其转换为另一个。使用 as cast 是进行运行时转换的一种方法,但在处理接口时还有更多选择,我们将在下一节看到。