creating command objects at run-time

By relying on a dictionary (e.g, std::unordered_map or std::map) that maps a command identifier (i.e., a std::string object) to a Command object, you can design a factory with dynamic registry for your Command objects.

First, extend Command by including another virtual member function, clone(), that allows us to implement The Prototype Pattern:

class Command {
   // ...
   virtual std::unique_ptr<Command> clone() const = 0;

The clone() virtual member function does what its name suggests: it clones the object. That is, SpawnEnemyCommand would override Command::clone() in the following way:

class SpawnEnemyCommand : public Command {
   // ...
   std::unique_ptr<Command> clone() const override {
      // simply create a copy of itself
      return std::make_unique<SpawnEnemyCommand>(*this);

This way, your command objects can be copied polymorphically through the Command interface – i.e., you don’t need to know the concrete type of the command to be copied. All you need to do to copy a Command object is to call its clone() virtual member function. For example, the following function copies the Command passed as an argument regardless of the underlying concrete type:

std::unique_ptr<Command> CopyCommand(const Command& cmd) {
    return cmd.clone();

With this in mind, you are ready to design a factory for command objects, CommandFactory, that supports dynamically registering your command objects:

class CommandFactory {
   void registerCommand(std::string id, std::unique_ptr<Command>);
   std::unique_ptr<Command> createCommand(std::string id) const;
   std::unordered_map<std::string, std::unique_ptr<Command>> registry_;

It all boils down to a std::unordered_map<std::string, std::unique_ptr<Command>> data member. Indexing this data member by a command identifier, which is an std::string, we retrieve a Command object – This is the prototype object we will use for cloning.

The registerCommand() member function adds a Command prototype to the registry:

void CommandFactory::registerCommand(std::string cmdId, std::unique_ptr<Command> cmd) {
   registry_[cmdId] = std::move(cmd);

The createCommand() member function clones the Command prototype corresponding to the requested command identifier:

std::unique_ptr<Command> CommandFactory::createCommand(std::string cmdId) const {
   auto const it = registry_.find(cmdId);
   if (it == registry_.end())
      return nullptr; // no such a command in the registry

   auto const& cmdPtr = it->second;
   return cmdPtr->clone();

As an example program:

auto main() -> int {
   CommandFactory factory;
   factory.registerCommand("spawn", std::make_unique<SpawnEnemyCommand>());

   // ...

   auto cmdPtr = factory.createCommand("spawn");

You can also extend this factory to add support for dynamically deregistering your already-registered Command prototypes.

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top