Keep the configuration out of the code

Posted on Oct 27, 2021, three minutes to read.

Sometimes, it’s not a complex design pattern but a small idea you borrow from a different language that will get the job done.

On one project, I had a factory method where an appropriate class is used based on a configuration:

class Style {
public:
    void apply(Application *app);
    static void install(Application *app, const Config &config);
protected:
    //methods like
    virtual std::map<std::string, std::string> getMap() const = 0;
    virtual std::vector<std::string> getList() const = 0;
}

void Style::install(Application *app, const Config &config) {
    if (config.setting1 == 'a') {
        Style1().apply(app);
    } else if (config,setting1 == 'b') {
        Style2().apply(app);
    }
}

void Style::apply(Application *app) {
    //called on subclasses of the Style class, calls overloaded methods from the implementation
    //getMap();
    //getList();
    //apply the style on app
}

Over time this block of code grew substantially. The amount of possible values for setting1 skyrocketed. Also, other settings came into play.

My initial idea was to use a map of possible Style classes, pick one based on a setting1 value and go from there as I would in Python:

map = {
    'a': Style1,
    'b': Style2
}
map[setting1]().apply(app)

This approach turned out tricky to pull off in C++. Nevertheless, it brought me an idea. After an investigation, I found out the Style classes are internally effectively JSONs - that is, they only contain a bunch of properties we read one way or another. Instead of selecting an appropriate class, I can pick a JSON file, load the values from the JSON instead of a Style class and process that the way I do now.

With that in mind, it was sufficient to replace all the Style classes with a JSON object. I store the JSON in resources for all configurations. It is then enough to extract maps and lists from the JSON and directly process those. As a result, we no longer need the inheritance nor mangroves of conditions.

class Style {
public:
    static void install(Application *app, const Config &config);
}

void Style::install(Application *app, const Config &config) {
    //load maps and lists from the JSON
    //use the code from original apply() to process those maps and lists
    //apply the style on the app
}

Did you find this useful?

You can unsubscribe at any time by clicking the link in the footer of our emails. For information about our privacy practices, please visit our website.

I use Mailchimp as our marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp's privacy practices here.