I riferimenti circolari sono obbligatori per alcune strutture di dati, come gli elenchi collegati doppiamente. Quindi, i riferimenti circolari non sono intrinsecamente malvagi.
Le dipendenze circolari tra le librerie, i progetti, i sottosistemi o i livelli di solito sono davvero pessimi. Tali dipendenze spesso implicano l'inizializzazione e amp; problemi di terminazione, che tendono a ostacolare la libreria o il sottosistema affidabili e abbattere.
I riferimenti circolari tra classi strettamente correlate sono di solito ok.
Indipendentemente dal fatto che i riferimenti circolari siano ok, dipende in qualche modo dalla lingua che stai usando, ad esempio se ha una garbage collection o meno. Potrebbe essere necessario fare attenzione durante la costruzione e amp; distruzione.
Tuttavia, alcuni ritengono che queste circolarità debbano essere rimosse mediante il refactoring, trovando una sub-entità e promuovendola a un'entità completa, vedi link
Distinguiamo anche diversi tipi di riferimenti su quanto strong sia la dipendenza che ne deriva (più strong è la dipendenza, peggio sarebbe una circolarità).
Quando una classe ha una variabile di istanza di un'altra classe, crea un riferimento semplice (dati). Quando una classe (i suoi metodi) invoca metodi di istanza di un'altra classe che forma un semplice riferimento (di codice). Le circolarità tra queste non sono generalmente così negative.
Tuttavia, se è possibile convertire una o più classi in un'interfaccia che le rende più liberamente accoppiate e indebolisce i problemi di circolarità. Oppure, alternativamente, suddividere una delle classi in entità più piccole può anche rompere la circolarità.
Tuttavia, quando una classe invoca un metodo statico o un costruttore di un'altra classe, questo forma una dipendenza diretta più strong che è più di un semplice riferimento al tipo teorico.
Nel tuo esempio, RubberDuck
, esegue new DuckBehavior()
, che forma una dipendenza più strong rispetto a quando si fa riferimento a un'altra classe tramite l'indirizzamento indiretto di istanze o interfacce. Se DuckBehavior
allora, aveva anche un riferimento al campo statico, al metodo statico o al costruttore di Duck
o RubberDuck
, questo avrebbe formato una dipendenza circolare relativamente strong che potrebbe sollevare qualche sopracciglio. Nel tuo esempio, no, utilizza un campo di istanza / proprietà name
(presumibilmente di Duck
, che RubberDuck
presumibilmente si estende, non mostrato).
Andando oltre, se un metodo statico fa riferimento a un campo statico, a un metodo oa un costruttore di un'altra classe, questo rende un riferimento ancora più strong (da statico a statico tra il tipo di dipendenza più strong). I cicli qui sarebbero disapprovati. (Ovviamente, in generale, la statica è generalmente disapprovata in OOP: c'è molta energia nell'area dell'iniezione di dipendenza e l'inversione del controllo per eliminare i legami stretti causati dall'uso diretto dei costruttori.)
Le dipendenze più forti tendono ad essere osservabili in fase di compilazione, vale a dire mediante l'analisi statica della gerarchia di classi e del grafico delle chiamate. Le circolarità qui tendono ad essere problematiche. Circolarità più deboli che emergono solo in fase di esecuzione e tendono ad essere per lo più ok, specialmente nei linguaggi raccolti con garbage.
Can I pass a reference of Duck
to the DuckBehavior
class when I'm constructing it?
Sì, penso che sia ok.
Or is this anti pattern circular reference?
No, non penso che crei una strong dipendenza circolare dal tipo problematico; tenendo a mente, naturalmente, si potrebbe ancora avere un accoppiamento più sciolto con qualche refactoring.