Tre varianti di riferimenti circolari tra oggetti: come scegliere?

3

Sto progettando un grafico di dipendenza degli oggetti del mio programma e di tanto in tanto appare un'ambiguità tra le varianti di design.

Immagina due oggetti che hanno un riferimento tra loro. Ovviamente, almeno un riferimento dovrebbe essere assegnato dopo l'inizializzazione dell'oggetto (ad esempio, tramite un metodo di sottoscrizione) e un altro facoltativamente può essere una dipendenza diretta.

Ecco un diagramma degli oggetti

Non sono sicuro di aver usato UML corretto, quindi ecco la mia descrizione:

1) Entrambi gli oggetti hanno metodi di abbonamento / vincolo. Uso:

A a = new A();    
B b = new B();    
a.Set(b);    
b.Set(a);

2) ObjectB è un componente di ObjectA :

A a = new A(new B());     

// somewhere, possibly in a's method :    
b.Set(a);

3) Terzo è in realtà un opposto del secondo, non c'è bisogno di spiegare.

Nella mia situazione posso usare uno di questi e il mio programma funzionerà, ma voglio alcune ragioni teoriche. Possono essere trovati?

    
posta astef 23.05.2014 - 10:46
fonte

2 risposte

3

Disclaimer - Non voglio discutere se un riferimento ciclico è buono o cattivo - IMHO ci sono situazioni in cui questo tipo di design è al 100% appropriato, e per il gusto di non iniziare una guerra santa, supponiamo che questo sia un caso del genere qui.

Le tue 3 alternative non differiscono molto - almeno, non in lingue come C # o Java. Quello che ottieni è due oggetti aeb, ognuno con un riferimento l'uno all'altro. Questo vale anche per (2) - se vedi B come componente di A è più una questione del tuo punto di vista (poiché le classi sono sempre tipi di riferimento in queste lingue).

Quindi l'unica differenza tra (2) e (1) è se si passa uno dei due riferimenti all'interno del costruttore o usando un metodo separato Set . Scegli l'alternativa "costruttore" se vuoi che i tuoi riferimenti ciclici vengano inizializzati immediatamente, dopo la costruzione dell'oggetto, assicurandoti che siano inizializzati il più presto possibile. Usa l'alternativa Set se hai bisogno dell'opzione per ritardare l'inizializzazione (forse vuoi usare singoli oggetti A senza la necessità di fornire sempre un oggetto B - e viceversa - in alcuni scenari).

Nota finale: è molto più facile prendere una tale decisione in termini di contesto, conoscendo i nomi delle classi, la semantica, il contesto e lo scenario di utilizzo.

    
risposta data 23.05.2014 - 12:05
fonte
1

Come sempre, fare una domanda migliora la mia comprensione del problema.

La principale differenza tra queste tre varianti è lifetime dell'oggetto. Che cosa è assente quando parliamo di classi, ma è molto importante in caso di oggetti.

Nella prima variante, le vite sono indipendenti. Entrambi gli oggetti possono vivere l'uno senza l'altro. La conoscenza di a di b inizia a ricevere un messaggio su di esso, lo stesso della conoscenza di b di a . La responsabilità di connettere le vite di tali oggetti cade su un terzo oggetto, quindi questa variante deve essere utilizzata solo quando c'è un reale bisogno di avere a e b viventi l'uno senza l'altro. Questo è raro, in realtà. Sto ancora cercando un esempio semplice e buono.

Nella seconda variante a conosce b durante tutta la vita. Diciamo che a possiede b e usiamo qualcosa come il modificatore readonly di C # per un campo con riferimento a b . Ma b non può possedere a , perché sarà impossibile istanziarli. In altre parole, i grafici delle componenti dirette non possono avere cicli. Invece, possiamo usare il diritto di a per configurare i propri componenti, per accedere a se stesso a b . In questo caso non abbiamo bisogno di un terzo oggetto per collegare questi due, ma dobbiamo complicare lo stato di a con un campo aggiuntivo come isInitialized che deve essere controllato ogni volta che usiamo a .

    
risposta data 23.05.2014 - 14:43
fonte

Leggi altre domande sui tag