2009-07-22 1 views
7

Così ho iniziato a imparare Qt 4.5 e ho trovato che il meccanismo Signal/Slot era di aiuto. Tuttavia, ora mi trovo a considerare due tipi di architettura.Chiamate di funzione/slot rispetto a chiamate dirette

questo è quello che avrei usato

class IDataBlock 
{ 
    public: 
    virtual void updateBlock(std::string& someData) = 0; 
} 

class Updater 
{ 

    private: 
    void updateData(IDataBlock &someblock) 
    { 
     .... 
     someblock.updateBlock(data); 
      .... 
    } 
} 

Nota: il codice inline per brevità.

Ora con segnali solo potessi

void Updater::updateData() 
{ 
    ... 
    emit updatedData(data); 
} 

Questo è più pulita, riduce la necessità di un'interfaccia, ma devo fare solo perché ho potuto? Il primo blocco di codice richiede più digitazione e più classi, ma mostra una relazione. Con il secondo blocco di codice, tutto è più "senza forma". Qual è il più desiderabile, e se è un caso per caso, quali sono le linee guida?

risposta

9

L'emissione di un segnale costa pochi switch e alcune chiamate di funzione aggiuntive (a seconda di cosa e come è collegato), ma l'overhead dovrebbe essere minimo.

Il fornitore di un segnale non ha alcun controllo su chi siano i suoi clienti e anche se tutti hanno effettivamente ricevuto il segnale entro il tempo di emissione.

Questo è molto conveniente e consente il disaccoppiamento completo, ma può anche portare a problemi quando l'ordine di esecuzione è importante o quando si desidera restituire qualcosa.

Non passare mai i puntatori ai dati temporanei (a meno che tu non sappia esattamente cosa stai facendo e anche allora ...). Se è necessario, passa l'indirizzo della variabile membro - Qt fornisce un modo per ritardare la distruzione dell'oggetto fino a quando non vengono elaborati tutti gli eventi.

I segnali potrebbero anche richiedere l'esecuzione del ciclo di eventi (a meno che la connessione non sia diretta, penso).

In generale hanno molto senso nelle applicazioni guidate dagli eventi (in realtà diventa molto fastidioso senza di loro).

Se si utilizza già Qt in un progetto, utilizzarli definitivamente. Se la dipendenza da Qt è inaccettabile, boost ha un meccanismo simile.

3

C'è un'altra differenza. Il n. 1 è strettamente collegato all'interfaccia IDataBlock e la classe Updater deve conoscere "someblock". # 2 può essere accoppiato in ritardo tramite una chiamata di connessione (o più, inclusi i disconnessi), che porta a un approccio più dinamico. # 2 agisce come un messaggio (pensa Smalltalk/ObjC) e non una chiamata (pensa a C/C++). I messaggi possono anche essere soggetti a più spedizioni, il che richiede che la mano implementi quella caratteristica al punto # 1.

La mia preferenza sarebbe quella di utilizzare segnali/slot a causa della loro flessibilità, a meno che le prestazioni del codice o la necessità di dati di ritorno immediati non lo consentano (o la dipendenza da Qt non è auspicabile).

2

Le due forme possono sembrare simili. Funzionalmente, è vero. In pratica, stai risolvendo un problema più grande. In questi casi, circostanze esterne causeranno la non equivalenza di queste due soluzioni.

Un caso comune è capire la relazione tra sorgente e sink. Si conoscono persino? Nel tuo primo esempio, updateData() deve avere il sink passato. Ma cosa succede se il trigger è un pulsante della GUI [Aggiorna dati]? I pulsanti sono componenti generici e non dovrebbero conoscere IDataBlock.

Una soluzione è ovviamente aggiungere un membro m_someblock a Updater. Il pulsante aggiornerà ora qualsiasi membro si trovi in ​​Updater. Ma è davvero questo che intendevi?