防止破坏界面传递的对象

时间:2010-11-12 07:38:37

标签: delphi interface

我对Delphi和Delphi中的接口没有多少经验。

示例:

IListModel = interface
    function At(row, col : Integer) : String;
end;

MyModel = class(TInterfacedObject, IListModel)
public
    function At(row, col : Integer) : String;
    procedure ManipulateA;
    procedure ManipulateBogus;
end;

有一个视图可以显示实现IListModel接口的对象。

View = class(TForm)
public
    constructor Create(model : IListModel); reintroduce;
end;

我的应用拥有MyModel实例

MyApp = class({...})
strict private
    model : MyModel;
public
 // ...
end;

在应用程序中我创建模型并使用它。

procedure MyApp.LoadModel;
procedure MyApp.OnFoo;
begin
    model.ManipulateBogus;
end;

现在,我想显示数据

procedure MyApp.ShowModel;
var
    v : View;
begin
    v := View.Create(model); // implicit to IListView > refCount=1
    v.ShowModal;
    FreeAndNil(v);
    // refCount = 0
    // oops, my model is dead now
end;

我想知道解决这个问题的最佳方法是什么。 在MyApp中我可以同时拥有两个实例模型:MyModel AND通过IListModel接口。 或者我可以引入一个新的接口IMyModel并通过MyApp类中的此接口保存模型。我必须使用ShowModel方法中的Supports(...)来获取IListModel接口。 或者我从另一个非引用基类(TInterfacedPersistent或自写类)派生MyModel类。还有其他想法吗?

在这种情况下使用界面的最佳方法是什么?

编辑: 非引用计数基类:

function NonRefCountingObject.QueryInterface(const IID: TGUID;
                                             out Obj): HResult;
begin
  if GetInterface(IID, Obj) then
    Result := S_OK
  else
    Result := E_NOINTERFACE;
end;

function NonRefCountingObject._AddRef: Integer;
begin
    Result := -1;  // no reference counting
end;

function NonRefCountingObject._Release: Integer;
begin
    Result := -1;  // no reference counting
end;

这个实现是否正常?

2 个答案:

答案 0 :(得分:7)

如果要使用接口附带的引用计数,则只应通过接口引用该对象。除了通过接口之外没有对象的引用,也不会自己释放对象。

或者你可以通过重写_AddRef和_Release来禁用引用计数,并像你习惯的那样销毁对象。这就是TComponent所做的。

或者保持引用计数,但是当您像对象一样引用它时调用AddRef和Release。

修改

使用const参数可以防止引用计数更新并加快代码速度:

constructor Create(const model : IListModel); reintroduce;

答案 1 :(得分:1)

如果需要Interfaces和object引用,只需从TInterfacedPersistent(在Classes.pas中声明)而不是TInterfacedObject派生。请注意,您必须确保在释放实例时仍未保留任何接口引用。