2010-11-12 8 views
4

Je n'ai pas beaucoup d'expérience avec les interfaces Delphi et Delphi du tout.Prévenir la destruction de l'objet passé par l'interface

Exemple:

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; 

Il y a une vue qui peut visualiser des objets qui mettent en œuvre l'interface IListModel.

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

Mon application contient une instance MyModel

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

Dans l'application je crée le modèle et travailler avec elle.

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

Maintenant, je veux montrer les données

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; 

Je me demande quelle est la meilleure façon de résoudre ce problème. Dans MyApp, je pouvais contenir à la fois le modèle d'instance: MyModel ET via l'interface IListModel. Ou je pourrais introduire une nouvelle interface IMyModel et maintenir le modèle par cette interface dans la classe MyApp. J'ai dû utiliser si Supports (...) dans la méthode ShowModel pour obtenir l'interface IListModel. Ou je dérive la classe MyModel à partir d'une autre classe de base non refactoring (TInterfacedPersistent ou une classe auto-écrite). D'autres idées?

Quelle est la meilleure façon de travailler avec des interfaces dans de telles situations?

Edit: Une classe de base de comptage non ref:

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; 

Est-ce ok la mise en œuvre?

Répondre

7

Si vous souhaitez utiliser le comptage de références fourni avec les interfaces, vous devez uniquement référencer cet objet via les interfaces. Aucune référence à l'objet autre que via les interfaces et ne libérez pas l'objet vous-même. Ou vous pouvez désactiver le comptage des références en remplaçant _AddRef et _Release et détruire l'objet comme vous en avez l'habitude. C'est ce que TComponent fait.

Ou conservez le compteur de références, mais appelez AddRef et Release lorsque vous le référencez comme un objet.

modifier

à l'aide d'un paramètre const empêche la mise à jour de comptage de référence et des vitesses de votre code:

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

Thx pour votre réponse. Est-il sûr de remplacer TInterfacedObject ou la classe de base TComponent avec la classe NonRefCountingObject de ma modification? Cette implémentation est-elle correcte? – hansmaad

+0

Oui, c'est correct –

+1

@hansmaad: Ce que Lars veut dire dans sa première phrase, c'est que vous devriez remplacer 'model: MyModel' dans' MyApp' par avec 'model: IListModel'.Cela fait en sorte que 'MyApp' conserve une référence (jusqu'à ce que' MyApp' meurt, alors le refcount de 'model' est diminué, quand ce refcount devient zéro, il est automatiquement libéré). –

1

Si vous avez besoin à la fois, les interfaces et des références d'objets, dérive simplement de TInterfacedPersistent (déclarés dans les classes .pas) au lieu de TInterfacedObject. Sachez que vous devez vous assurer qu'aucune référence d'interface n'est encore en attente lorsque vous libérez l'instance.

+0

Y a-t-il un bon article d'introduction disponible n'importe où sur TInterfacedObject, TInterfacedPersistent, et hybrides objet/interface similaires? –