2

For example, I have something need to do depend on user input:

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;
}

now has option A and B,and it is violating open closed principle because when adding new condition,e.g.: option "C",needs to modify the if else statement in test.cpp. Is it possible to modify the code so that adding option "C" just adding a new file (class) and does not require to modify test.cpp?

I tried wrap the operation into a template class:

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

and try to call the template in main:

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

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

so that adding a new option only needs to add a new template, but it failed to compile because the template can accept constant string only, and even it works, add new option still require to modify test.cpp to add new #include statement. Is it possible to add new option by defining a new class/new file without editing existing source code?

  • It the question C++-specific? – COME FROM Aug 5 '16 at 6:13
  • I removed the C++ tag - though the examples are in C++, the question itself stays essentially the same in any other OO language. – Doc Brown Aug 5 '16 at 8:38
  • @DocBrown Not necessarily. Many ways of avoiding modifications to code rely on the use of frameworks that rely on reflection. E.g. in Java I could solve the problem by using Spring's automatic component discovery. C++ doesn't have any support for reflection so this isn't possible in C++. – Jules Aug 5 '16 at 9:04
  • @Jules: true, but that does not mean this question cannot be interpreted in a mainly language-agnostic manner. If someone wants to show an (probably overengineered) reflection solution or a template C++ solution to this simple question, he should add a remark about the language in his answer. – Doc Brown Aug 5 '16 at 9:58
5

Yes, it is possible to have a command-handling mechanism that doesn't require (extensive) editing to add a new command. It does require some additional infrastructure though.

The basis is that

  • you have a common interface for your commands through which you can ask which string triggers the command and through which you can tell the command to do its work:

    class ICommand {
    public:
      std::string getTrigger() const = 0;
      void execute() = 0;
    };
    
  • at the point where you read the user input, you have a collection of ICommand implementations available that you can loop over and there you would call execute on those commands whose trigger matches the current input.

Adding a new command would involve creating a new class that implements the ICommand interface and adding (an instance of) that new class to the list of known commands.

  • Or having some method to register new commands with the command handler (and having something external creating a standard list) – Richard Tingle Aug 5 '16 at 9:55
2

Bart's gives the common OO approach, C++ (and many other languages) will also admit a more functional approach:

first lets change the list of commands to some sort of associative container, std::map or std::multimap, this will allow look up of commands to be better than O(n) and means the trigger is not needed as part of the command interface

second, we remove the trigger from the command interface and now are left with an interface that is equivalent to std::function so lets use that instead

we can now add commands to our container by giving the trigger as the key and a lambda as the action, no need for any new classes/interfaces

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.