2013-04-10 8 views
5

faccio questo molto:Alternative al passaggio di un puntatore a se stessi per gli oggetti Possiedi

class Child{ 
    Control*parent; 
public: 
    Child(Control*theParent):parent(theParent){} 
}; 

class Control{ 
Child child; 
void makeChild(){ child=Child(this); } 
//Control() : child(this) { } //another example 
} 

modo che il controllo possiede e gestisce il bambino, ma il bambino ha ancora riferimento al controllo padre.

Quando leggo argomenti generali sugli schemi di progettazione del programma, ecc., Sembra che questo metodo di organizzazione degli oggetti non sia particolarmente raccomandato. Capisco che ci sono dei rischi, per esempio non vuoi che il tuo child abusi dei suoi genitori facendo fare al genitore cose che solo il genitore dovrebbe decidere di fare da solo; in tal caso, sembra facile prevenirlo assicurandosi che i metodi critici del genitore siano privati. Ma allora potresti avere un altro controller che gestisce il genitore, nel qual caso alcuni metodi dovrebbero essere pubblici, e ora tuo figlio ha accesso anche a quelli, quando in realtà solo qualche altro controller dovrebbe manipolarli.

Quindi posso vedere come questo può essere pericoloso.

Ma la mia domanda è, qual è un'alternativa comune? È necessario un genitore per possedere un figlio, ma è necessario che il bambino sia in grado di notificare occasionalmente il genitore delle cose. Come, se non quanto sopra?

Objective-C ha la NSNotificationCenter che permette notifiche senza riferimenti in realtà di passaggio, ma questo rende anche facile creare problemi organizzativi (perché è il mio bambino l'invio di questa notifica, e che sta per riceverlo?)

+0

Bella domanda, lo faccio molto e mi sono chiesto (e mi chiedo ancora) se c'è un'alternativa per questo. –

+1

Dovrebbe essere più simile a 'Control(): child (this) {}', non dovrebbe? –

+0

@KerrekSB sì ho digitato lo pseudocodice senza compilarlo; l'ho corretto – johnbakers

risposta

2

Li può separare da un'interfaccia:

class IListener { 
public: 
    virtual void notify (int somevalue) = 0; 
    ~IListener() {}; 
} 

class Child{ 
private: 
    IListener *listener; 
public: 
    Child(IListener *theListener):listener(theListener){} 
}; 

class Control: public IListener { 
private: 
    Child child; 
public: 
    makeChild(){ child(this) }; 
    virtual void notify(int someValue) { doSomething(someValue);}; 
} 

(Questa è una versione semplice del modello di osservatore, BTW).

+1

Il tuo 'notify' nella classe base dovrebbe essere' virtuale', ma per il resto questo sembra buono – maditya

+0

Grazie. Ultimamente ho scritto troppo Java. – Mikkel

+1

Preferirei utilizzare un adattatore con delega sull'ereditarietà e fornire un'interfaccia di controllo ristretta piuttosto che un osservatore generico, ma altrimenti questo è il modo in cui andrei (c: –

2

Sembra che tu stia cercando il modello di osservatore.

Nel modello di osservazione, un oggetto mantiene un elenco di dipendenti (noti anche come osservatori) e li notifica delle modifiche come richiesto. Nel tuo caso, la classe Control è l'osservatore e la classe Child è il notificatore.

La libreria Boost ha un meccanismo segnale/slot che può essere utilizzato per implementare questo: http://www.boost.org/doc/libs/1_49_0/doc/html/signals/tutorial.html#id3137144

C'è un esempio di utilizzo di questo su SO: Complete example using Boost::Signals for C++ Eventing

+0

Idea interessante; Avrei pensato che ci sarebbe stato comunque un modo per fare qualcosa nel linguaggio principale. – johnbakers

+0

Non ancora, ma ho sentito che sarà discusso per C++ 14. – maditya

+0

Dai un'occhiata all'altra risposta per un esempio di pattern di osservatore senza boost in C++ – johnbakers

0

Lanciare un'altra idea sul ring, sembrerebbe che un Friend class può fare molto anche con questo.

I metodi a cui un bambino non dovrebbe avere accesso vengono effettuati private o protected. In questo modo il bambino non può fare alcun danno che tu non vuoi che faccia.

Quindi se hai bisogno di un'altra classe per gestire il tuo controller genitore, la tua classe genitore trasforma quell'altra classe in friend in modo che possa accedere a tutti quei metodi privati ​​trattenuti dal bambino.

0

Quando leggo argomenti generali sugli schemi di progettazione del programma, ecc., Sembra che questo metodo di organizzazione degli oggetti non sia particolarmente raccomandato.

Questo è così sbagliato, a causa di inversion of control. Potresti averlo creato come variabile membro Child. Martin Fowler ha un very nice article che spiega un tipo di inversione di controllo (iniezione di dipendenza).

Ecco un esempio che spiega brevemente come implementare l'iniezione di dipendenza (dipendenza iniettato attraverso costruttore):

#include <iostream> 

struct B 
{ 

    virtual ~B(){} 
    virtual void foo() = 0; 
}; 
struct A1 : public B 
{ 
    virtual ~A1(){} 
    virtual void foo() 
    { 
     std::cout<<"hello"<<std::endl; 
    } 
}; 
struct A2 : public B 
{ 
    virtual ~A2(){} 
    virtual void foo() 
    { 
     std::cout<<"test"<<std::endl; 
    } 
}; 

struct C 
{ 
    C(B &b_) : b(b_){} 

    void bar() 
    { 
     b.foo(); 
    } 

    B &b; 
}; 

#define SAY_HI 

int main() 
{ 
#ifdef SAY_HI 
    A1 a; 
#else 
    A2 a; 
#endif 
    C c(a); 

    c.bar(); 
} 

Se ci pensate modelli di progettazione, si noterà alcuni di loro utilizzare una sorta di inversione di controllo. Qui ci sono alcuni ben noti (da this link):


A proposito, quello che hai è chiamato chain of responsibility.

+0

essenzialmente quello che ho dimostrato è l'iniezione di dipendenza, quindi puoi spiegare cosa intendi quando dici che lo sto facendo "erroneamente"? il tuo esempio è anche iniezione, tramite costruttore.che è incluso nel mio esempio anche come esempio. – johnbakers

Problemi correlati