La vista comune OO è che un'interfaccia stabilisce un unico contratto che definisce come oggetti conformi a tale interfaccia vengono utilizzati e come si comportano. L'idioma o il motivo NVI, non so mai quando uno diventa l'altro, propone un cambiamento di quella mentalità dividendo l'interfaccia in due contratti separati:
- come l'interfaccia è da utilizzare
- quali classi derivate devono offrire
Questo è in qualche modo particolare C++ (infatti qualsiasi lingua con ereditarietà multipla), dove l'interfaccia può infatti contenere codice che si adatta dall'interfaccia esterna --Come utenti vedono me-- e l'interfaccia interna - come sono implementato.
Questo può essere utile in diversi casi, in primo luogo quando il comportamento è comune ma può essere parametrizzato solo in modi specifici, con uno scheletro di algoritmo comune. Quindi l'algoritmo può essere implementato nella classe base e nei punti di estensione negli elementi derivati. Nelle lingue senza ereditarietà multipla, questo deve essere implementato dividendo in una classe che implementa l'algoritmo basato su alcuni parametri conformi ad una diversa interfaccia 'privata'. Sto usando qui 'privato' nel senso che solo la tua classe userà quell'interfaccia.
Il secondo uso comune è che utilizzando il linguaggio NVI, è semplice strumento del codice da modificare solo a livello di base:
class Base {
public:
void foo() {
foo_impl();
}
private:
virtual void foo_impl() = 0;
};
Il costo aggiuntivo di dover scrivere dispatcher foo() { foo_impl(); }
è piuttosto piccolo e consente di aggiungere in seguito un meccanismo di blocco se si converte il codice in un'applicazione multithread, si aggiunge la registrazione a ciascuna chiamata o un timer per verificare la quantità di implementazioni diverse in ciascuna funzione ... Poiché il metodo effettivo implementato nelle classi derivate è privato a questo livello, è garantito che tutte le chiamate polimorfiche possono essere strumentate in un singolo punto: la base (questo non blocca le classi estendibili da rendendo foo_impl
pensiero pubblico)
void Base::foo() {
scoped_log log("calling foo"); // we can add traces
lock l(mutex); // thread safety
foo_impl();
}
Se i metodi virtuali erano pubbliche, quindi non si poteva intercettare tutte le chiamate ai metodi e sarà necessario aggiungere che la registrazione e filo di sicurezza per tutti le classi derivate che implementano l'interfaccia .
fonte
2010-07-22 09:41:51
! = Membri pubblici. La tua interfaccia è la tua _documentation_, non il tuo file di intestazione. –