Delphi:如何将子接口实现委托给子对象?

时间:2010-08-14 14:13:30

标签: delphi interface delegation delphi-5

2 个答案:

答案 0 :(得分:9)

您必须为创建的子对象添加字段实例:

type
  TRobot = class(TInterfacedObject, IStream)
  private
     FStream: TRobotStream;
     function GetStream: IStream;
  public
     property Stream: IStream read GetStream implements IStream;
  end;

destructor TRobot.Destroy;
begin
  FStream.Free; 
  inherited; 
end;

function TRobot.GetStream: IStream;
begin
  if FStream = nil then 
    FStream := TRobotStream.Create(Self);
  result := FStream;
end;

<强>更新 正如您已经猜到的那样,TRobotStream应该来自TAggregatedObject。声明应该是:

type
  TRobotStream = class(TAggregatedObject, IStream)
   ...
  end;

没有必要提及IUnknown。

在TRobot.GetStream中,行result := FStream执行了一个隐含的FStream as IStream,因此也不需要写出来。

FStream必须声明为TRobotStream而不是IStream,因此当TRobot实例被销毁时它可以被销毁。注意:TAggregatedObject没有引用计数,因此容器必须处理它的生命周期。

更新(Delphi 5代码):

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, activex, comobj;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    procedure Button1Click(Sender: TObject);
  private
    procedure LoadRobotFromDatabase(rs: IStream);
  public
  end;

type
  TRobotStream = class(TAggregatedObject, IStream)
  public
    { IStream }
    function Seek(dlibMove: Largeint; dwOrigin: Longint;
       out libNewPosition: Largeint): HResult; stdcall;
    function SetSize(libNewSize: Largeint): HResult; stdcall;
    function CopyTo(stm: IStream; cb: Largeint; out cbRead: Largeint; out cbWritten: Largeint): HResult; stdcall;
    function Commit(grfCommitFlags: Longint): HResult; stdcall;
    function Revert: HResult; stdcall;
    function LockRegion(libOffset: Largeint; cb: Largeint; dwLockType: Longint): HResult; stdcall;
    function UnlockRegion(libOffset: Largeint; cb: Largeint; dwLockType: Longint): HResult; stdcall;
    function Stat(out statstg: TStatStg; grfStatFlag: Longint): HResult; stdcall;
    function Clone(out stm: IStream): HResult; stdcall;
    function Read(pv: Pointer; cb: Longint; pcbRead: PLongint): HResult; stdcall;
    function Write(pv: Pointer; cb: Longint; pcbWritten: PLongint): HResult; stdcall;
  end;

type
  TRobot = class(TInterfacedObject, IStream)
  private
    FStream: TRobotStream;
    function GetStream: IStream;
  public
    destructor Destroy; override;
    property Stream: IStream read GetStream implements IStream;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  rs: IStream;
begin
  rs := TRobot.Create;
  LoadRobotFromDatabase(rs); //dummy method, just to demonstrate we use the stream
  rs := nil;
end;

procedure TForm1.LoadRobotFromDatabase(rs: IStream);
begin
  rs.Revert; //dummy method call, just to prove we can call it
end;

function TRobotStream.Clone(out stm: IStream): HResult;
begin
end;

function TRobotStream.Commit(grfCommitFlags: Integer): HResult;
begin
end;

function TRobotStream.CopyTo(stm: IStream; cb: Largeint; out cbRead, cbWritten: Largeint): HResult;
begin
end;

function TRobotStream.LockRegion(libOffset, cb: Largeint; dwLockType: Integer): HResult;
begin
end;

function TRobotStream.Read(pv: Pointer; cb: Integer; pcbRead: PLongint): HResult;
begin
end;

function TRobotStream.Revert: HResult;
begin
end;

function TRobotStream.Seek(dlibMove: Largeint; dwOrigin: Integer;
  out libNewPosition: Largeint): HResult;
begin
end;

function TRobotStream.SetSize(libNewSize: Largeint): HResult;
begin
end;

function TRobotStream.Stat(out statstg: TStatStg; grfStatFlag: Integer): HResult;
begin
end;

function TRobotStream.UnlockRegion(libOffset, cb: Largeint; dwLockType: Integer): HResult;
begin
end;

function TRobotStream.Write(pv: Pointer; cb: Integer; pcbWritten: PLongint): HResult;
begin
end;

destructor TRobot.Destroy;
begin
  FStream.Free;
  inherited;
end;

function TRobot.GetStream: IStream;
begin
  if FStream = nil then
     FStream := TRobotStream.Create(Self);
  result := FStream;
end;

end.
enter code here

答案 1 :(得分:3)

您的类不需要委派从任何特定类继承。如果已经实现了适当的方法,您可以从TObject继承。我将保持简单,并使用TInterfacedObject进行说明,它提供了您已经识别的3种核心方法。

此外,您不应该需要TRobotStream = class(TAggregatedObject, IUnknown, IStream)。您可以简单地声明IStream继承自IUnknown。顺便说一句,我总是给我的接口一个GUID(按下组合Ctrl + Shift + G)。

根据您的特定需求,可以应用多种不同的方法和技术。

  • 委托接口类型
  • 委托课程类型
  • 方法别名

最简单的委托是通过接口。

TRobotStream = class(TinterfacedObject, IStream)

TRobot = class(TInterfacedObject, IStream)
private
  //The delegator delegates the implementations of IStream to the child object.
  //Ensure the child object is created at an appropriate time before it is used.
  FRobotStream: IStream;
  property RobotStream: IStream read FRobotStream implements IStream;
end;

或许有一点需要注意:

  • 确保您委派的对象具有适当的生命周期。
  • 请务必提及受委托人。请记住,接口是引用计数的,并且一旦计数降至零就会被销毁。 这实际上可能是您头痛的原因