Michal Kohutek

[C++] Using factories without writing any factories

Factories are a very useful pattern in object oriented programming. They however require including and indexing all these classes at one place, requiring modification when a new creatable subclass is added. This trick allows to avoid this annoyance.

Factory pattern is one of the most known design patterns in object oriented programming. A factory creates one of multiple possible classes derived from a common parent and returns it as the common parent. This can be used for example to generate a structure of classes using configuration where the actual types are written as strings.

A factory, however, can be tedious to maintain at times. It needs to include all classes it constructs (slowing down the compilation) and contain a list of all classes together with the conditions to pick them. Adding new classes requires editing the factory as well, which leans on violating the single responsibility principle.

However, there is a way to avoid this. The trick lies in not writing the factory.

A typical factory

This is a typical factory function with no particlarly interesting content:

std::unique_ptr<Widget> createWidget(const std::string& name) {
  if (name == "Text") return std::make_unique<TextWidget>();
  else if (name == "Input") return std::make_unique<InputWidget();
  else if (name == "Slider") return std::make_unique<InputSlider();
  else if (name == "Combo") return std::make_unique<ComboWidget();
  else throw(std::runtime_error("Unknown widget " + name));
}

It can be a source file with a header to avoid including all the subclasses to everything that uses the factory. If the list was longer, an unordered_map could be better than a long else if chain.

What could be better

The factory usually needs to be defined in its own source and header. Also, adding new classes requires remembering they have to be added into the factory as well (because it doesn’t follow the single responsibility principle by acting as some sort of virtual constructor of the common parent class.

It would be ideal if the specific classes were not included anywhere and the factory didn’t need to be declared at all. And it can be done.

The idea

The tools to define classes that can work with any possible class are templates. This can be used to create objects this way:

std::unique_ptr<Widget> widget =
                       GenericFactory<Widget>::createChild(name);

Invoking the factory was the easy part. Now, how to make specific subclasses make the factory take them into consideration?

The subclasses are defined in different compilation units (=different source files) and making them available at the location of factory invocation would defeat the purpose. This can be dealt with using the singleton pattern, a way to have a global instance of an object, accessible from anywhere (it has to be properly encapsulated to prevent its abuse). Here’s an example of a singleton:

class Singleton {
  Singleton() = default; // Private constructor
  Singleton(Singleton&&) = delete; // Prevent it from being moved
  Singleton(const Singleton&) = delete; // Prevent copying
public:
  static Singleton& get() { // Can be done better in C++17
    static Singleton instance; // Constructs one at first invocation
    return instance; // Returna always the one copy
  }
  // Some functional content here
};

Singletons can be templated to have an instance for every set of template parameters.

The singleton is a way to share data between unrelated compilation units. But it’s done only at runtime, individual subclasses have to register themselves into the singleton during the program’s initialisation. A registration function each of them implements would again require some location with all these classes included and listed, defeating the purpose again.

Now, is there a way to execute code without it being called from main or from anything whose call stack begins with main? Well, actually, there is one. Initialisation of global variables. It has horrendous potential for abuse, so it has to be used with great care.

Global variables are initialised before main is called and can be set to the return value of a function (if it’s a dynamically loaded library added to the program later, it’s done when they are loaded). A function that registers the class into the singleton. An inconvenience of this approach is that it’s not possible to create more groups of creatable objects, but it’s unlikely to be ever needed. So each subclass needs this call in its source file (cannot be in a header, because the global variable would be defined once for every location it’s included in):

namespace NothingToSeeHere {
  const bool definedTextWidget = GenericFactory<Widget>::
                                    registerChild<TextWidget>("Text");
}

The global variable itself serves no purpose, improperly changing it or accessing it cannot do any damage.

This code is really confusing, so it should be better wrapped in a macro:

REGISTER_CHILD_INTO_FACTORY(Widget, TextWidget, "Text");

It’s also convenient to create classes that use the specific subclasses in a similar, specific type agnostic way. This can be done by indexing classes by their runtime typeids (which requirs them to be polymorphic, but this would be pointless if they weren’t), downcasting them and giving them as arguments to constructors to the other classes that use them. It’s not trivial to do, but it requires no special tricks.

std::unique_ptr<WidgetView> view =
             GenericSecondaryFactory<WidgetView,
             std::shared_ptr<Widget>>::createChild(widget);

The implementation

The index of creatable classes can be an unordered map of std::function instances containing lambdas that call specific constructors.

A proper implementation should also support constructor arguments. This can be done quite easily using argument packs.

The actual implementation is at my github page. Only the generic_factory.hpp file is needed, the rest is just for testing or demonstration.

Using the provided implementation

Because the classes aren’t included at all, they don’t need headers at all:

class TextWidget : public Widget {
  std::string _text;
  float _fontSize;
public:
  TextWidget(const nlohmann::json& source) {
    fromJson(source);
  }
  void fromJson(const nlohmann::json& source) override {
    _text = source["text"];
    _fontSize = source["size"];
  }
  void draw(DrawingContext& context) override {
    context->drawText(_text, _fontSize);
  }
};

REGISTER_CHILD_INTO_FACTORY(Widget, TextWidget, "Text", const nlohmann::json&);

The factory can be used for example like this:

std::unique_ptr<Widget> widget =
              GenericFactory<Widget, const nlohmann::json&>
                   ::createChild(it.key(), it.value());

If there is some specific class that uses a specific subclass of the created class, it has to be one somewhat differently.

First, the used subclass needs a header, because it’s used by the other class (unless they are in the same file). The rest assumes that class TextView has this kind of access to class TextWidget and is its friend. The definition of class TextView:

class TextView : public WidgetView {
  TextWidget* _widget;
  std::vector<uint8_t> _serialised;
public:
  TextView(TextWidget* widget) : _widget(widget) {
  }
  const std::vector<uint8_t>& serialise() override {
    if (_serialised.empty()) {
      _serialised = base64(_widget._text);
      _serialised.push_back(':');
      for (char it : std::to_string(_widget._fontSize))
        _serialised.push_back(it);
    }
    return _serialised;
  }
};

REGISTER_SECONDARY_CHILD_INTO_FACTORY(WidgetView, Widget, TextView, WidgetView);

Now, instances of any subclasses can be created this way:

std::unique_ptr<Widget> widget =
              GenericFactory<Widget, const nlohmann::json&>
                   ::createChild(it.key(), it.value());
std::unique_ptr<WidgetView> view =
              GenericSecondaryFactory<WidgetView, Widget*>
                   ::createChild(widget.get());

Note that this is just an example, I am not making any GUI system and I have never written the other functions. A working code used for testing is a part of the Github repository.

Conclusion

Factories are a very useful pattern in object oriented programming. They however require including and indexing all these classes at one place, requiring modification when a new creatable subclass is added.

This trick allows to avoid this annoyance by having the classes register themselves into a generic class that doesn’t have to be defined for every type of object created. See it on my github.

Post release notes:

  • This is not a remake of Boost DI. Boost DI serves to initialise a bunch of interdependent modules in proper order according to code that declares it. This tool initialises components that are not interdependent, but does it without any code that lists them. Boost DI needs to have all the components included, this tool doesn’t.
  • I later learned that this pattern is called self-registering factory, because the classes register themselves into it. Unlike other implementations I have seen, this one is generic.
  • If using Microsoft Visual Studio, the self-registering will not work if the object files are added from a .lib file

Leave a Reply

Your email address will not be published. Required fields are marked *