Richiamo di diverse funzioni di libreria in base al parametro

4

Sto scrivendo una classe piuttosto ampia in cui l'utente può specificare in fase di esecuzione se desidera utilizzare l'algoritmo A o B di una libreria di terze parti e. Fondamentalmente c'è solo una chiamata di funzione diversa nella scelta di A o B, ma questa funzione è chiamata in molti posti diversi nel codice.

Vorrei omettere di dover scrivere

if (user_chose_A) {
  call_A_algo();
} else {
  call_B_algo();
}

su tutto il mio codice e mi chiedo quale sia una buona soluzione per il mio problema (in C ++ 11).

Stavo pensando di memorizzare due puntatori di funzione (std :: function), uno per l'algoritmo A e uno per B e quindi avere una funzione nella mia classe che restituisce il puntatore di funzione corretto.

Dato che il mio scenario sembra una situazione piuttosto comune, mi sto chiedendo quale sia la migliore pratica qui.

    
posta user695652 10.05.2016 - 00:11
fonte

2 risposte

6

L'approccio comune orientato agli oggetti per nascondere i dettagli di implementazione (in questo caso A_algo e B_algo sono dettagli di implementazione) è trovare una connessione tra le due (o tra tre o più) funzioni e definire un nuovo generico interfaccia (in C ++ una pura classe astratta), che viene quindi istanziata da una sorta di fabbrica .

In termini orientati agli oggetti, questo è per lo più indicato come modello di progettazione dell'adattatore, quando fornisci la stessa interfaccia per due cose apparentemente diverse.

class AlgorithmAdapter
{
public:
    virtual void run() const = 0;
};

class AlgorithmOneAdapter : public AlgorithmAdapter
{
public:
    void run() const
    {
        call_A_algo();
    }
};

class AlgorithmTwoAdapter : public AlgorithmAdapter
{
public:
    void run() const
    {
        call_B_algo();
    }
};

// some function
void runsAlgorithm(AlgorithmAdapter const & algorithm)
{
    algorithm.run(); // <- does not care whether it's algo_A or algo_B,
                     // but it knows, the run method is available
}

Avresti quindi la factory, che conterrebbe un'istruzione switch , fornendo un'implementazione concreta dell'interfaccia AlgorithmAdapter , sulla quale sapresti che il metodo run è disponibile.

Perché è buono?

Delega la decisione dell'algoritmo dal tuo livello di business logic a una classe factory, che è responsabile solo della creazione del grafo di oggetti (vedi separazione di preoccupazioni ).

Ne vale la pena?

Creazione di 3 o più classi solo per poter astrarre la chiamata? Forse anche no, dipende dalle tue esigenze.

C'è un modo più semplice?

Ho menzionato una fabbrica, che è praticamente una semplice funzione% / metodo switch/case . Puoi fare lo stesso senza dover definire le 3 nuove classi di adattatori, definendo una nuova funzione / metodo, inserendo la decisione in base al valore del parametro che viene passato e usando questo metodo per tutto il codice (lavorare direttamente con le funzioni è approccio più procedurale rispetto a quello orientato agli oggetti)

È molto più veloce da fare, ma un po 'mixa le responsabilità (con questo approccio avresti una funzione che farebbe entrambe le cose, prendere la decisione su quale algoritmo dovrebbe essere scelto ed eseguirlo).

Potresti anche passare un puntatore a funzione come parametro a una funzione, quindi in una funzione ignorerai l'algoritmo specifico, ma anche in questo caso, dovresti comunque decidere quale algoritmo scegliere da qualche parte . Non importa quanto duramente proverai, ci sarà sempre posto in un codice che saprà come collegare i componenti insieme in base ad alcune regole, è inevitabile.

    
risposta data 10.05.2016 - 00:31
fonte
1

Il Pattern di fabbrica viene utilizzato per gestire situazioni simili, ma nel contesto di OOP. Avresti essenzialmente una classe standalone per ogni algoritmo, un'interfaccia che implementano in modo che possano essere usati in modo intercambiabile, e un metodo che utilizza argomenti (l'input dell'utente, in questo caso) per decidere quale classe istanziare. La tua soluzione puntatore di funzione è essenzialmente lo stesso concetto, meno l'OOP.

    
risposta data 10.05.2016 - 00:28
fonte

Leggi altre domande sui tag