Piuttosto che avere un codice riusabile, hai un codice che è intercambiabile.
Un esempio di vita reale che utilizza i picchietti DI e Adapter. Supponiamo che tu abbia una classe, che gestisce i dati. Non recupera i dati, ma li gestisce. Potremmo chiamarlo semplicemente DataHandler.
class DataHandler
{
public:
void doSomethingWithData() {}
protected:
private:
};
Quando inizi a utilizzare DataHandler nella tua app, lo usi per gestire i dati da un database SQL. Quindi DataHandler
avrà bisogno di un'istanza di detta classe.
class SqlDatabaseDataRetriever
{
public:
Data getData() { }
protected:
private:
};
class DataHandler
{
public:
DataHandler(SqlDatabaseDataRetriever& dataRetriever)
{
_dataRetriever = dataRetriever;
}
void doSomethingWithData()
{
Data data = this->_dataRetriever.getData();
}
protected:
SqlDatabaseDataRetriever _dataRetriever;
private:
};
Ma se successivamente decidessi, non vuoi accedere al database direttamente tramite SqlDatabaseDataRetriever
, quindi crei un'API e crei una nuova classe che viene utilizzata per gestire la richiesta tramite la tua API e recupera i dati da essa .
Quindi vogliamo utilizzare la classe DataHandler
con il nostro nuovo ApiDataRetriever
, ma attualmente il nostro DataHandler
utilizza una classe diversa. Potresti semplicemente riscrivere il tuo codice, iniettare invece ApiDataRetriever
, ma c'è una soluzione migliore.
Creerai una classe astratta, che erediterà tutti i tuoi DataRetriever, inserirai questa classe astratta e utilizzerai i suoi metodi.
class DataRetriever
{
public:
virtual Data getData() = 0;
protected:
private;
}
class SqlDatabaseDataRetriever : public DataRetriever
{
public:
virtual Data getData() { }
protected:
private;
}
class ApiDataRetriever : public DataRetriever
{
public:
virtual Data getData() { }
protected:
private;
}
class DataHandler
{
public:
DataHandler(DataRetriever& dataRetriever)
{
_dataRetriever = dataRetriever;
}
void doSomethingWithData()
{
Data data = this->_dataRetriever.getData();
}
protected:
DataRetriever _dataRetriever;
private:
};
Poiché la funzione nella classe genitore è definita come pura virtuale, deve essere implementata in classe figlio e poiché si sta iniettando la classe genitore, ma questa non può essere istanziata, si otterrà sempre una classe soggetto che ha il metodo genitore , che puoi usare senza vincoli.