2010-11-12 62 views
4

我对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和通过IListModel接口。 或者我可以引入一个新的接口IMyModel,并通过MyApp类中的这个接口保存模型。我必须使用ShowModel方法中的Supports(...)来获取IListModel接口。 或者我从另一个非refcounting基类(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; 

这是实现好不好?

回答

7

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

或者您可以通过覆盖_AddRef和_Release来禁用引用计数,并像您惯用的那样销毁对象。这是TComponent所做的。或者保持引用计数,但在引用AddRef和Release时像引用对象一样调用AddRef和Release。

编辑

使用常量参数防止引用计数更新和加速你的代码:

constructor Create(const model : IListModel); reintroduce; 
+0

Thx为您的答案。用编辑中的NonRefCountingObject类替换TInterfacedObject或TComponent基类是否安全?这个实现是否正确? – hansmaad 2010-11-12 08:35:00

+0

是的,正确的 – 2010-11-12 11:05:42

+1

@hansmaad:Lars在他的第一句话中的含义是,你应该用'model:IListModel'替换'MyApp'中的'model:MyModel'。这确保'MyApp'保持一个引用(直到'MyApp'死亡;然后'model'的refcount减少,当refcount变为零时,它被自动释放)。 – 2010-11-12 12:07:45

1

如果同时需要,接口和对象引用,只是从TInterfacedPersistent获得(在类中声明.pas)而不是TInterfacedObject。请注意,在释放实例时,您必须确保没有接口引用仍然存在。

+0

在TInterfacedObject,TInterfacedPersistent和类似的对象/接口混合体的任何地方有没有很好的介绍性书写? – 2010-11-12 22:01:02