Design: Richiamo alla classe genitore


13

Quando si modella un oggetto con figli è comune includere i figli tramite composizione, come membro della classe genitore. A volte, tuttavia, i bambini devono dire qualcosa al genitore, devono chiamare una funzione del genitore. Come si può ottenere ciò usando C ++? Alcune opzioni sono:

  1. Rendi globale la classe genitore, quindi gli oggetti figlio saranno in grado di chiamare le funzioni membro dell'oggetto genitore.

  2. Iniettare l'oggetto genitore come puntatore o riferimento in ogni oggetto figlio. Quindi, quando il bambino deve dire qualcosa all'oggetto genitore, può sempre farlo perché ha una variabile membro che può usare.

Quali sono altri metodi per farlo? Esiste un modello di progettazione generale o un nome per questo genere di cose?

Nota che sono interessato a idee e soluzioni in C ++ perché i dettagli saranno diversi in altri linguaggi orientati agli oggetti. Ad esempio il punto 2 sopra menziona "puntatori o riferimenti" ed entrambi sono possibili solo in C ++. Il C ++ ha funzionalità linguistiche che non sono presenti in altre lingue, pertanto le implementazioni di una soluzione al problema incorporeranno potenzialmente queste funzionalità linguistiche rendendo la soluzione diversa da ciò che qualcuno potrebbe trovare in un'altra lingua.


puoi aggiungere un esempio? È un esempio valido per la tua domanda? Hai un oggetto ordine (= genitore) con gli ordini (figli) e vuoi aggiornare il totale dell'ordine quando viene modificata una quantità di ordine? o stai pensando a qualcosa di completamente diverso?
k3b,

@ k3b Sì, questo è un esempio valido. Alcune informazioni nel bambino sono cambiate richiedendo al genitore di fare qualcosa.
sashang,

basta aggiungere alcuni parametri del costruttore e membri dei dati di riferimento a ciascuna classe figlio.
tp1,

Il bambino ha bisogno di sapere tutto sul genitore o sarebbe delegatesufficiente un semplice ?
Julien Guertault,

Risposte:


16

Per prima cosa, questo può essere un odore di codice. Il punto di usare la composizione per il genitore / i figli è che il genitore conosce i figli ma non viceversa. Soprattutto se la relazione è più di un "contiene" di "è composto da".

Un riferimento al genitore è possibile e abbastanza comune in C ++. In altre lingue, un oggetto funzione o un evento viene più spesso utilizzato per consentire al bambino di comunicare cose che gli estranei potrebbero voler sapere. Questo è un tipo comune di modello di pubblicazione-sottoscrizione. Sospetto che ciò che è più idiomatico dipenda dalla versione di C ++ che stai utilizzando e dagli standard della tua base di codice.


Nella mia situazione è un odore di codice. Bella risposta.
Martin Pfeffer,

3

Come altri hanno sottolineato, l'idea di base di iniettare l'oggetto genitore come puntatore o riferimento è la strada da percorrere - in linea di principio.

Ciò ha uno svantaggio: si ottiene una dipendenza ciclica tra genitore e figlio. Se vuoi evitarlo, definisci una classe base astratta (un'interfaccia) IParentda cui eredita il tuo genitore. IParentdovrebbe contenere i metodi come funzioni virtuali che il bambino desidera chiamare. Quindi, iniettare il genitore come riferimento a IParent. Ciò semplifica notevolmente il test unitario del bambino, poiché ora è possibile sostituire facilmente l'oggetto principale con un oggetto simulato.

Se tuo figlio ha bisogno di chiamare solo una funzione dell'oggetto genitore, una IParentclasse completa potrebbe essere sovradimensionata. In questo caso, sarà sufficiente iniettare un puntatore alla funzione membro nel figlio o un oggetto functor che incapsula quella funzione membro.


2

Quello che puoi fare è mantenere un riferimento al genitore nella classe figlio, per composizione. In questo modo, il bambino conosce il suo genitore e può invocare metodi pubblici su di esso.

Quindi andrei con l'opzione 2. Devi stare attento però, quando un figlio viene rimosso dal genitore, devi rimuovere il riferimento al genitore nel figlio e puntarlo a null (o un nuovo genitore, se ha uno). Oppure potresti semplicemente eliminare l'oggetto figlio, a seconda del contesto.


1

Passa loro un riferimento o un puntatore al genitore. Puoi renderli amici del genitore o rendere pubblico il metodo chiamato. Se non vuoi fare nulla di quanto sopra, puoi passare loro un oggetto "bridge" che espone uno dei metodi del genitore come pubblico ed è esso stesso una classe nidificata priva del genitore (quindi ha accesso a ogni metodo genitore ). Questo può essere un po 'troppo complesso in molte situazioni, tuttavia.


1

2) Iniettare l'oggetto genitore come puntatore o riferimento in ogni oggetto figlio. Quindi, quando il bambino deve dire qualcosa all'oggetto genitore, può sempre farlo perché ha una variabile membro che può usare.

È un'opzione perfettamente praticabile. Tutte le lingue moderne hanno una funzione che può essere utilizzata per fare riferimento a un'altra lingua.


1

Esiste un approccio simile con leggere variazioni ma che offre vantaggi:

Supponiamo che il genitore A contenga il componente C.

Nel componente C, dichiarare InterfaceC e mantenerne il riferimento. Questa è l'interfaccia del componente con il mondo esterno.

Il genitore A implementa InterfaceC e imposta il suo riferimento nel componente C. Il componente C vede il genitore A come InterfaceC.

L'idea è: un componente parla all'esterno usando la sua interfaccia.

I vantaggi dell'utilizzo di questo rispetto all'impostazione diretta del genitore sono:

Di 'che il componente fa qualcosa e deve avvisare il genitore. Chiama l'interfaccia. Successivamente, decidi di voler cambiare il genitore. Al componente non interessa affatto e non verrà apportato alcun cambiamento.

Di 'in seguito che vuoi avvisare molti oggetti di un evento. È sufficiente creare un elenco di InterfaceC e aggiungere riferimenti ad esso.

Svantaggi: una classe genitrice finirà per implementare molte interfacce (penso che questo sia un vantaggio, dato che guardando la dichiarazione di classe, so immediatamente chi ne parla)


0

Nota che questo è specifico per c #. Non so se c ++ ha qualcosa di simile.

Se hai una gui-form con pulsanti, di solito hai un approccio diverso usando Event-Subscribtion, noto anche come Observer_pattern o Publish-iscriviti pattern .

Il pulsante di solito non conosce la forma specifica in cui vive. Al contrario, il pulsante attiva o pubblica un evento e il modulo riceve una notifica sottoscritta e può reagire di conseguenza.

Oltre alle indicazioni, questo meccanismo può essere utilizzato in ogni relazione paren-child

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.