Può "fare qualcosa dipende dall'input" obbedire a principio aperto aperto?

2

Ad esempio, ho bisogno che qualcosa dipenda dall'input dell'utente:

test.cpp

#include <iostream>
#include <fstream>
int main(){
    std::string input;
    std::cin >> std::noskipws >> input;

    if(input=="A"){
        std::cout << "A selected" << std::endl;
    }else if(input=="B"){
        std::ofstream myfile;
        myfile.open ("test_log.txt");
        myfile << time(NULL);
        myfile.close();
        std::cout << "time saved" << std::endl;
    }else{
        std::cout << "error" << std::endl;
    }
    return 0;
}

ora ha l'opzione A e B, e viola i principi chiusi aperti perché quando si aggiunge una nuova condizione, ad esempio: l'opzione "C", è necessario modificare l'istruzione if else in test.cpp. È possibile modificare il codice in modo che aggiungendo l'opzione "C" solo aggiungendo un nuovo file (classe) e non sia necessario modificare test.cpp?

Ho provato a racchiudere l'operazione in una classe template:

char a[]="A";
template<>
struct st<a>{
    st(){
        std::cout << "A selected" << std::endl;
    }
};

e prova a chiamare il modello in main:

#include "A.h"
#include "B.h"

int main(){
    std::string input;
    std::cin >> std::noskipws >> input;
    st<input.c_str()>();
    return 0;
}

così che aggiungere una nuova opzione ha solo bisogno di aggiungere un nuovo modello, ma non è riuscito a compilare perché il modello può accettare solo una stringa costante, e anche funziona, aggiungere una nuova opzione richiede ancora di modificare test.cpp per aggiungere un nuovo # include la dichiarazione. È possibile aggiungere nuove opzioni definendo una nuova classe / nuovo file senza modificare il codice sorgente esistente?

    
posta ggrr 05.08.2016 - 06:05
fonte

2 risposte

5

Sì, è possibile avere un meccanismo di gestione dei comandi che non richiede modifiche (estese) per aggiungere un nuovo comando. Tuttavia richiede alcune infrastrutture aggiuntive.

La base è che

  • hai un'interfaccia comune per i tuoi comandi attraverso la quale puoi chiedere quale stringa attiva il comando e tramite la quale puoi dire al comando di fare il suo lavoro:

    class ICommand {
    public:
      std::string getTrigger() const = 0;
      void execute() = 0;
    };
    
  • nel punto in cui leggi l'input dell'utente, hai a disposizione una raccolta di implementazioni ICommand che puoi eseguire il loopover e chiamerai execute su quei comandi il cui trigger corrisponde all'attuale input.

L'aggiunta di un nuovo comando implicherebbe la creazione di una nuova classe che implementa l'interfaccia ICommand e aggiungendo (un'istanza di) quella nuova classe all'elenco di comandi noti.

    
risposta data 05.08.2016 - 09:15
fonte
2

Bart's dà l'approccio OO comune, il C ++ (e molti altri linguaggi) ammetterà anche un approccio più funzionale:

prima consente di modificare l'elenco dei comandi in una sorta di contenitore associativo, std :: map o std :: multimap, questo consentirà di cercare i comandi in modo migliore di O (n) e significa che il trigger non è necessario come parte dell'interfaccia di comando

in secondo luogo, rimuoviamo il trigger dall'interfaccia di comando e ora restiamo con un'interfaccia equivalente a std :: function, quindi usiamolo invece

ora possiamo aggiungere comandi al nostro contenitore assegnando il trigger come chiave e un lambda come azione, senza bisogno di nuove classi / interfacce

    
risposta data 05.08.2016 - 11:21
fonte

Leggi altre domande sui tag