2009-06-22 13 views
15

Sono abbastanza nuovo per il processo di progettazione OO, quindi per favore abbiate pazienza con me ....Domanda disegno OO - genitore/figlio (i) - circolare?

Ho due entità che ho bisogno di modellare come classi, li chiamano padre e figlio (che è abbastanza vicino al reale dominio problematico). Un genitore avrà uno o più figli - non ho interesse, in questa applicazione, in genitori senza figli.

Dove il mio cervello sta uscendo a pranzo dipende dal fatto che devo essere in grado di trovare l'uno dall'altro. Nel mio database posso implementarlo con una normale relazione di chiave esterna, e la natura basata su set di SQL rende facile trovare tutti i figli per un dato genitore, o il genitore per un dato bambino. Ma come oggetti ...?

I pensare che che il genitore dovrebbe portare una raccolta (elenco, qualunque) di bambini. Penso anche che ogni bambino dovrebbe portare un riferimento al suo genitore. La natura circolare dei riferimenti, tuttavia, mi fa male alla testa.

Am I:

  • Sulla strada giusta?
  • Completamente spento? Se sì, cosa dovrei fare in modo diverso?

Questo sarà quasi certamente implementato in VB.NET, ma sono un modo di tagliare il codice ancora.

Modifica dopo 8 risposte: tutte le

Grazie. È stato difficile scegliere solo una risposta da accettare.

Per chiarire un paio di cose che sono state interrogate nelle risposte:

  • genitori e bambini sono molto diversi entità - non c'è successione relazione a tutti. Ho scelto i nomi che ho fatto perché sono davvero molto vicini al dominio del problema reale e ora vediamo che è una fonte di confusione da una prospettiva OO .
  • La gerarchia è profonda solo un livello - I bambini non avranno mai figli all'interno dell'applicazione.

Grazie ancora.

+2

Anche i bambini possono avere figli o una gerarchia a livello singolo? Se è multilivello, devi guardare il modello Composito. –

+0

Non si tratta solo di una questione temporale vs spazio con memorizzazione di collegamenti nei nodi? Dipende dai vincoli ... se lo spazio non è un problema, la memorizzazione dei collegamenti è ok, purché abbiano integrità –

+0

@Harper Shelby - È a livello singolo. I bambini non avranno mai figli propri (in questa applicazione). Bella domanda, però. – RolandTumble

risposta

11

I riferimenti circolari sono fini e assolutamente standard quando si crea una struttura ad albero. di HTML Document Object Model (DOM), per esempio, ha le proprietà di padre e figlio su ogni node in un albero DOM:

interface Node { 
    // ... 
    readonly attribute Node  parentNode; 
    readonly attribute NodeList childNodes; 
    // ... 
} 
+0

+1 ... Buon esempio se la definizione circolare non importa in * alcune * lingue (... prova questo in C: P ...) a causa dell'allocazione automatica –

+2

Questo non è un riferimento circolare. – Randolpho

+0

@Randolpho - no è una definizione circolare –

0

Mi sembra che tu sia sulla buona strada per un cattivo progetto. La tua architettura non dovrebbe mai avere riferimenti circolari.

Probabilmente dovresti riesaminare il motivo per cui i tuoi figli hanno bisogno di un riferimento al genitore e viceversa. Mi sporgerei verso il genitore che ha una collezione di bambini. È quindi possibile aggiungere funzionalità al genitore per verificare se un oggetto figlio è figlio dell'istanza.

Una migliore explination del gol potrebbe essere un po 'più utile pure ...

EDIT

ho letto un po' di più (e ascoltato commenti) ...e si scopre che sono abbastanza nel torto. I riferimenti circolari in effetti hanno il loro posto fintanto che stai attento con loro e non lasciarli sfuggire di mano.

+0

"La tua architettura non dovrebbe mai avere riferimenti circolari." Perché no? Legittimamente curioso. –

+0

In teoria, un riferimento circolare come quello potrebbe portare a un codice che scorre infinitamente. Supponiamo che tu abbia un codice che carica il tuo genitore, quindi carica i figli, che carica di nuovo il genitore, che carica di nuovo il bambino, e ... e su ... –

+0

Gli strumenti ORM spesso generano riferimenti circolari per le associazioni per impostazione predefinita. Non indica necessariamente un difetto di progettazione. – womp

1

Se ho capito che gli oggetti di P contengono una matrice di oggetti P-> c [] che rappresentano i bambini. E ogni nodo P senza figli è una foglia ... con ogni P contenente P-> P '(il genitore).

La soluzione specificata, con i genitori che contengono riferimenti a bambini e viceversa, elimina la necessità di attraversare l'albero per ottenere antenati di un dato bambino e figli di un nodo. Questo è davvero solo un albero su cui puoi eseguire tutti i tipi di link e algoritmi per attraversarlo ed enumerarlo. Che va bene!

Suggerisco di leggere il capitolo sugli alberi in The Art of Computer Programming per un eccellente e approfondito sguardo alle strutture arboree e ai modi efficienti di enumerare genitori e figli.

2

Stai parlando di una gerarchia di classi, in cui la classe genitore conosce le sue classi figlio?

Si dovrebbe evitare a tutti i costi.

Per impostazione predefinita, una classe figlio sa tutto su una classe genitore, perché è un'istanza della classe genitore. Ma per avere una classe genitrice a conoscenza delle sue classi figlio è necessario che la classe figlia sappia anche tutto su ogni altra classe figlia. Questo crea una dipendenza tra un bambino e ogni altro figlio di quella classe. Questo è uno scenario impossibile da mantenere che corrisponderà a causa di problemi in futuro, se riuscirai persino a compilare o eseguire, il che in molte lingue non sarà il caso.

Detto questo, mi sembra che tu non stia cercando di fare una gerarchia di classi, ma una gerarchia di collezioni, cioè un albero. In tal caso, sì, sei sulla strada giusta; è un paradigma comune. Il nodo genitore ha una collezione di nodi figli e il nodo figlio ha un riferimento al nodo genitore.

Il fatto è? Sono tutti della stessa classe! Ecco un esempio molto semplice in C#:

public class Node 
{ 
    public readonly Node Parent; // null Parent indicates root node 
    public readonly List<Node> Children = new List<Node>(); 
    public Node(Node parent) 
    { 
    Parent = parent; 
    } 
    public Node() 
    { 
    parent = null; 
    } 
    public void AddChild(Node node) 
    { 
    Children.Add(node); 
    } 
} 

Ho la sensazione che questo è ciò che siete veramente dopo. Usando questo paradigma, si dovrebbe quindi sottoclasse il nodo per qualsiasi scopo nefasto si possa avere.

+2

Mi sembrava un contenimento piuttosto che una relazione di ereditarietà. – Robert

+0

@Robert: sono d'accordo, ma l'intervistatore non era molto chiaro, motivo per cui ho chiesto chiarimenti e modifiche. – Randolpho

+0

Le classi saranno diverse l'una dall'altra. I bambini non sono (molto) la stessa cosa dei genitori. Ma posso vedere dove all'inizio non ero tutto chiaro. – RolandTumble

8

Sembra che tu sia sulla strada giusta per me. Come per il modello di dominio, i genitori hanno figli e i genitori hanno genitori. Potrebbe essere necessario fare riferimento l'uno all'altro.

Non c'è niente di sbagliato nei riferimenti circolari, devi solo stare attento a quello che fai con loro. Dove ti troverai nei guai, gestisci le tue entità sul lato server in modo automatico quando le carichi dal database. Ad esempio, si recupera un oggetto Child dal database con una query. Includete le informazioni relative ai genitori? Includete i figli dei genitori?

Gli strumenti ORM come Lightspeed o Entity Framework di Microsoft generalmente si occupano di questo utilizzando le direttive "lazy loading". Prenderanno ciò di cui hai bisogno in un primo momento (così, quando recuperi un bambino, ottiene solo le proprietà figlio e l'ID del genitore). Se in seguito, si denota il genitore, esso va e recupera le proprietà padre e crea un'istanza dell'oggetto padre. Se in seguito, accederai alla sua collezione Children, poi andrà a prendere le informazioni rilevanti del bambino e creerà oggetti Child per quella raccolta. Fino a quando non ti servono, però, non lo popola.

2

Penso che sia ragionevole voler essere in grado di attraversare il grafico degli oggetti in questo modo. È difficile sapere se ne hai una ragione giustificabile dal tuo post, ma non credo che i riferimenti di per sé dimostrino un cattivo design.

2

Credo che tu sia sulla strada giusta. Perché la natura circolare dei riferimenti fa male alla testa? Qual è il problema fondamentale che stai riscontrando con uno Parent con riferimenti ai suoi figli e un Child con un riferimento al suo genitore?

+0

Immagino sia solo l'allenamento di tutti quegli anni di strutture normalizzate del tavolo ... – RolandTumble

+3

Ah, sì, capisco. Tieni presente che nel mondo SQL esiste un'ulteriore fonte di dati; il database vero e proprio che contiene le tabelle che possono essere interrogate; c'è un "riferimento in avanti" a livello di database per il genitore che viene utilizzato lì; nella tua struttura di classe, non esiste un riferimento così consultabile da cui cercare i genitori. Nella progettazione di oggetti, la normalizzazione può essere un errore, a causa dell'incapacità di interrogare i dati; i riferimenti devono essere espliciti. –

+0

che grande spiegazione concisa - grazie! – Skilldrick

1

Se i bambini mosto avere un genitore di solito richiedono solo un'istanza del tipo genitore il costruttore bambino.