本文假设你懂得 Delphi 的接口编程(关键词:Interface)
假设我们定义了一个接口 IA,它有一个或几个方法。这里假设这个接口定义只有一个方法。
然后,我们有两个不同的类,都实现了这个 IA 接口。但对其方法的实现,有点不一样。假设这两个类分别是 X 和 Y。也就是说,调用 X 的接口方法,和调用 Y 的同样接口的同名方法,得到的结果不同。这类似于对象继承的多态所要达到的目标。
然后,我们有一个类 Z,它也实现了接口 IA。但是,它不用真正地实现一次 IA 的方法所需要的代码,它仅仅是委托给 X 或者 Y 就可以了。为什么要这样做?理由大概有几点:
1. 这个 Z 除了需要实现接口 IA 所提供的方法,还需要提供其它一些方法。
2. 这个 Z 作为一些对象或者接口的封装,对外隐藏代码的复杂性。
如果这个 Z 是采用委托的方式,将自己实现的接口,委托给 X 或 Y,则在运行期,是可以动态切换到。这样一来,就可以根据不同的情况,调用相同的接口方法,获得不同的运行结果,实现不同的功能。这样的代码,可以避免一堆的 if.. else,也更方便将来增加新的功能,而无需去更改 Z 的代码。
详细演示代码,已经上传到 CNDEV 里面。这里是下载地址。
以下是部分代码:
unit UMyIntf;
{------------------------------------------------------------------------
接口委托及运行期动态更换的演示代码。
pcplayer 2017-5-31
------------------------------------------------------------------------}
interface
uses System.SysUtils, System.Variants, System.Classes;
type
IMyIntf = interface
['{9FC4FAA4-04F1-4799-9C30-BB444214E292}']
function Hello(const S: string): string;
end;
IHelloIndex = interface
['{C994DC32-D4CB-44F3-8A4D-7E3A6798A7DC}']
procedure SetMyIndex(const Value: Integer);
property MyIndex: Integer write SetMyIndex;
end;
TEngHello = class(TComponent, IMyIntf)
public
function Hello(const S: string): string;
end;
TChinaHello = class(TComponent, IMyIntf)
public
function Hello(const S: string): string;
end;
TMyHello = class(TComponent, IMyIntf, IHelloIndex)
private
FMyIntf: IMyIntf;
FMyIndex: Integer;
FEngHello: TEngHello;
FChinaHello: TChinaHello;
procedure SetMyIndex(const Value: Integer);
public
constructor Create(AOwner: TComponent); override;
property MyIntf: IMyIntf read FMyIntf implements IMyIntf;
property MyIndex: Integer write SetMyIndex;
end;
const
IID_IHelloIndex: TGUID = '{C994DC32-D4CB-44F3-8A4D-7E3A6798A7DC}';
IID_IMyIntf: TGUID = '{9FC4FAA4-04F1-4799-9C30-BB444214E292}';
implementation
{ TEngHello }
function TEngHello.Hello(const S: string): string;
begin
Result := 'Hello, ' + S;
end;
{ TChinaHello }
function TChinaHello.Hello(const S: string): string;
begin
Result := '你好, ' + S + ', 吃饭了吗?';
end;
{ TMyHello }
constructor TMyHello.Create(AOwner: TComponent);
begin
inherited;
FEngHello := TEngHello.Create(AOwner);
FEngHello.Name := 'EngHello';
FChinaHello := TChinaHello.Create(AOwner);
FChinaHello.Name := 'ChinaHello';
FMyIntf := FEngHello as IMyIntf;
end;
procedure TMyHello.SetMyIndex(const Value: Integer);
begin
FMyIndex := Value;
case value of
0: FMyIntf := FEngHello as IMyIntf;
1: FMyIntf := FChinaHello as IMyIntf;
end;
end;
end.