Programming

Making use of the Command Design Pattern

Design Pattern Game Design OOP System Design

The command pattern is one of my favorite design patterns. It allows you to parametrize actions and decouple the action from the one executing it.

pexels-photo-687811.jpeg pexels-photo-687811.jpeg

Some practical examples include setting up custom hotkeys for an application or the controls in a video game.

The following examples are done using Java, but can be accomplished with any Object Oriented language. You can download the full example of the command design pattern and others on GitHub at https://github.com/sethfair/design-patterns-java.

What is the problem?

Let’s go with a game character example for now. The controller and the character are tightly coupled. Here is a start to a BadGameController class that is not quite working right. To change the keys, you will need to change the code and re-compile the code.

public class BadGameController {
  Character character;
  void GameController() {
    character = new Character();
  }
  void handleWKey() {
    character.jump();
  }
  void handleDKey() {
    character.run();
  }
}

The code above will run when either the W or D keys are pressed. But it’s tightly coupled to the instantiated character.

Introducing the Command Pattern

We can solve it using the command pattern. Doing so will allow us to parameterize the actions and decouple the action from the client.

First, let’s create an interface:

public interface Command {
  public void execute();
}

Next, create a command class and implement the Command interface.

public class RunCommand implements Command {
    private final Character character;
    public RunCommand(Character character) {
        this.character = character;
    }
    @Override
    public void execute() {
        this.character.run();
    }
}

Then the original client code can be set it up.

public class GameController {
    HashMap<String, Command> commands = new HashMap<>();
    void registerKey(String key, Command c) {
        commands.put(key.toLowerCase(), c);
    }
    public void handleWKey() {
        commands.get("w").execute();
    }
    public void handleDKey() {
        commands.get("d").execute();
    }
}

We can then orchestrate the commands outside of the controller.

public class Game {
    Character character;
    Command runCommand;
    Command jumpCommand;
    public Game(GameController controller) {
        character = new Character();
        runCommand = new RunCommand(character);
        jumpCommand = new JumpCommand(character);
        controller.registerKey("w", jumpCommand);
        controller.registerKey("d", runCommand);
    }
}

Finally, bring it all together by instantiating a GameController class and a Game class.

class Practice {
    public static void main(String[]args){
        GameController controller = new GameController();
        Game game = new Game(controller);
        controller.handleDKey();
        controller.handleWKey();
    }
}

Calling the controller classes will call the execute methods. The controller is unaware of the implementation details of this command. This allows for a beautiful decoupling of the code.

The output will print as follows:

Character is running...
Character is jumping...

Conclusion

The GameController is completely separated by the commands that are passed in. All it needs to know is commands.get('w').execute(); This does not need to change at all going forward. The registration of different commands can change dynamically at runtime.

This allows what goes on in execute() to be completely abstracted away. It is then flexible to change as the application changes.