C/C++ Arena

Step 2 of 7

A factory registry

A factory creates objects by name: the name comes from a config file, a network message or a command line, and the result is returned through a base-class pointer. The naive version is a giant if/else chain that must be edited for every new type. Large codebases use a registry instead: a map from name to a creator function. Adding a type means registering one more entry, and the factory itself never changes.

#include <functional>
#include <iostream>
#include <map>
#include <memory>
#include <string>

struct Codec {
    virtual ~Codec() = default;
    virtual std::string encode(const std::string& s) const = 0;
};

struct Upper : Codec {
    std::string encode(const std::string& s) const override {
        std::string r = s;
        for (char& c : r) if (c >= 'a' && c <= 'z') c = char(c - 32);
        return r;
    }
};

struct Reverse : Codec {
    std::string encode(const std::string& s) const override { return {s.rbegin(), s.rend()}; }
};

int main() {
    std::map<std::string, std::function<std::unique_ptr<Codec>()>> registry;
    registry["upper"] = [] { return std::make_unique<Upper>(); };
    registry["reverse"] = [] { return std::make_unique<Reverse>(); };

    for (const char* name : {"reverse", "rot13", "upper"}) {
        auto it = registry.find(name);
        if (it == registry.end()) {
            std::cout << name << ": unknown codec\n";
            continue;
        }
        std::unique_ptr<Codec> c = it->second();       // call the creator
        std::cout << name << ": " << c->encode("hello") << "\n";
    }
}
reverse: olleh
rot13: unknown codec
upper: HELLO

How it works

Your task

Your turn: implement Factory::add (returns false if the name is already registered), Factory::create (returns nullptr for unknown names) and Factory::names (sorted).

Previous: Strategies as closures Next: Observers with weak_ptr