Newsgroup: it.comp.lang.delphi
Titolo: [D6][Lungo] Riferimenti circolari tra unit

Salve,
sto sviluppando 2 classi, una che descrive un Oggetto derivato da TList
(TWorkObjList) ed una che descrive gli oggetti contenuti nella lista
(TWorkObj).
La lista (TWorkObjList) e' tipizzata in modo da non dover fare il
casting qundo vi si accede (lo fa lei internamente).
Le due classi sono in due file diversi.
Ora desideravo inserire nella classe oggetto una proprieta' Parent di
tipo TWorkObjList in modo da permettere agli oggetti della lista di
accedere alle proprieta' della lista stessa.
Cosi' facendo mi sono trovato di fronte al problema dei riferimenti
circolari tra unit.
La lista TWorkObjList ha l'interfaccia cosi' definita:
type
  TWorkObjList = class(TList)
  private
    fOwnsObjects: boolean;
  protected
    function GetItems(Index: Integer): TWorkObj;
    procedure SetItems(Index: Integer; AWorkObj: TWorkObj);
  public
    constructor Create;
    destructor Destroy; override;
    function Add(AWorkObj: TWorkObj): Integer;
    function Extract(Item: TWorkObj): TWorkObj;
    function Remove(AWorkObj: TWorkObj): Integer;
    function IndexOf(AWorkObj: TWorkObj): Integer;
    function First: TWorkObj;
    function Last: TWorkObj;
    procedure Clear; override;
    procedure Insert(Index: Integer; AWorkObj: TWorkObj);
    property Items[Index: Integer]: TWorkObj read GetItems write
SetItems; default;
    property OwnsObjects: Boolean read fOwnsObjects write fOwnsObjects;
  end;
Ovviamente nelle interface uses facci riferimento alla unit di TWorkObj.
Per poter utilizzare l'oggetto TWorkObjList come tipo per la proprieta'
Parent dell'oggetto TWorkObj DEVO inserire il riferimento nella uses
interface della unit che definisce la classe TWorkObj. Cosi' facendo
pero' ho un riferimento circolare.
Al momento ho risolto cosi':
Definisco nella unit di TWorkObj una classe:
type
  TCustomWorkObjList = class(TList);
la classe nella TWorkObjList  la definisco:
  TWorkObjList = class(TCustomWorkObjList)
e la prorieta' Parent di TWorkObj la definisco cosi':
    property Parent: TCustomWorkObjList read fParent write fParent;
Questa soluzione funziona, ma e' corretta dal punto di vista dell'OO?
Saluti.
-- 
I'am what I'am, I do what I can

Ciao,
quando ho fatto questo genere di componenti ho scritto in una unica unit sia
l'oggetto Item sia l'oggetto contenitore.
Tipo:
tMioContenitore=Class;
tMioItem=Class
Private
fOwner: tMIoContenitore;
...
PUblic
Constructor Create(aOwner:tMioContenitore);
...
Property Owner: tMioContenitore read fOwner;
end;
tMioContenitore = Class(tList)
Private
Protected
PUblic
end;
Ciao
Giuseppe
"Setec Astronomy" <setec@_NO_NOSPAM_freemail.it> ha scritto nel messaggio
news:47m2b.263634$Ny5.8...@twister2.libero.it...


 ...
[cut]
Ti ringrazio, penso sia l'unica soluzione "elegante" disponibile in
delhi.


 
Perche'? Cioe', e' proprio necessario? In molti casi tale necessita' 
puo' essere causato da un errore di design (e ribadisco "puo'", non e' 
detto che lo sia).
-- 
Roal Zanazzi

 Questa soluzione funziona, ma e' corretta dal punto di vista dell'OO?
L'ideale sarebbe poter tenere tutto in una unica unit, ma dovendo
necessariamente tenere separati gli oggetti, direi che già la tua è una
buona soluzione.
L'unica nota, se TCustomWorkObjList non aggiunge niente a TList,
tanto vale, in TWorkObj dichiarare:
    property Parent: TList read fParent write fParent;
in questo modo eviti sicuramente il riferimento circolare nella sezione
interface. Magari poi nel codice ti serve fare il cast del Parent a
TCustomWorkObjList, però a questo punto la uses in implementation e quindi
viene a cadere il riferimento circolare.
Inoltre l'oggetto non è necessariamente legato a quel tipo di lista.
Una soluzione che mi viene in mente, un pò macchinosa ma certamente pulita
dal punto di vista OO:
--------------------------------
unit A
    TWorkObj = class
        [...]
    end;
--------------------------------
unit B
uses
    A;
    TWorkObjList = class;
    TWorkObjEx = class(TWorkObj)
    private
        FParent: TWorkObjList;
    public
        property Parent: TWorkObjList read FParent write FParent;
    end;
    TWorkObjList = class(TList)
        [...]
    end;
--------------------------------
Dovrebbe funzionare ;-)
Ciao,
Gianluca.
----------------------------------------------------------------
Brain Enterprise - Soluzioni digitali per il business...
http://www.brain-enterprise.com
----------------------------------------------------------------

Roal Zanazzi wrote:

Diciamo che normalmente non mi scontro con questo tipo di problemi, mi
piaccino i linguaggi fortemente tipizzati, non mi va di fare cast
espliciti se non obbligato (es. TList specilistica).


 
No, scusa colpa mia, non sono stato abbastanza chiaro.
Intendevo: perche' hai la necessita' di avere un legame bi-direzionale 
tra TWorkObj e TWorkObjList? Ossia, perche' hai bisogno di poter 
accedere da TWorkObj alla lista che lo contiene, tramite la proprieta' 
Parent?
-- 
Roal Zanazzi

 tramite la proprieta' Parent?
Perche' la classe TWorkObj e' la classe base che verra' derivata dagli
utilizzatori dei miei componenti, e vorrei che dalle sottoclassi siano
accessibili gli altri oggetti inseriti all'interno della lista che
contiene l'oggetto attuale.
E' un sistema internamente complesso, ma che per essere utilizzato
risulta facile ed intuitivo.
Saluti.
