0

The Problem

I would like to create a managing "overseer" class that connects several related object groups together where any particular group is able to be easily swapped for another using C++11 syntax.

A secondary goal of finding a good approach to code structure is to make the underlying code run quickly (since it will be used for conducting many simulations).

For context, this particular problem is something I have encountered in several other programming languages, but have not been able to find a great solution for in a compiled language.

Minimal Example

Classes

  1. Arcade
  2. ArcadeGame
  3. ArcadeScreen
  4. ArcadeMove
  5. ArcadePlayer

Problem Definition

  1. Suppose there exists an Arcade which sets up an ArcadeGameevery day for tournaments.
  2. Each ArcadeGame displays an ArcadeScreen as its output and accepts an ArcadeMove as its input.
  3. Each ArcadeMove and ArcadeScreen is unique to the ArcadeGame (e.g.: a GalaxySpacewarGame has different attributes in its ArcadeMove than a CombatFighterGame).
  4. An ArcadePlayer for any particular game must be able to take the ArcadeScreen as input and output a valid ArcadeMove for that game.
  5. The role of Arcade is to setup the ArcadeGame, ensure the ArcadePlayer is one that can actually play the game, and monitor the in-progress game to record the score of the player to a scoreboard.

Pseudocode of the listed classes

The following classes share these functions:

ArcadeGame
   Restart()
   ArcadeScreen GetScreen()
   InputMove(ArcadeMove a)
   int GetScore()
   bool IsOver()

ArcadePlayer
   ArcadeMove GetInput(ArcadeScreen a)

Arcade
   Arcade(ArcadeGame g) // constructor
   int PlayTournamentGame(ArcadePlayer p):
      g.Restart()
      while NOT activeTournamentGame.IsOver():
         ArcadeMove m = p.GetInput(g.GetScreen())
         g.InputMove(m)
      return g.GetScore()

The classes will then be used like so:

GalaxySpacewarGame spaceGame = new GalaxySpacewarGame(someConfigParams1);
GalaxySpacewarPlayer john = new GalaxySpacewarPlayer(someConfigParams2);
Arcade someArcade = new Arcade(spaceGame)
for(int i = 0; i < 100; i++):
   std::cout << PlayTournamentGame(john) << std::endl;

Attempted Approaches

  • I was taking a look at type erasure specifically as a way of ensuring the Arcade class does would not require knowledge of the ArcadeScreens for any of its games but do not see an easy way to enforce compile-time validation to ensure the ArcadePlayer is able to play that specific game. I am also unfamiliar with this specific design approach and would like to ask for a second opinion on whether it applies in this case.
  • I have also taken a look at the visitor and double dispatch patterns, but it does not look like any of those alone would be useful for this kind of architecture.

1 Answer 1

1

Sounds like you're describing the mediator pattern.

I'm not sure about your compile-time validation requirement. If you have an ArcadeGame class that takes an ArcadePlayer, I'm not sure access control can be enforced at compile-time without a custom preprocessor step or just encoding the rules in your build process. For example, if you were using Makefiles, you'd have an asteroids target that spec'd which ArcadePlayer(s) could play it.

2
  • In the case of a mediator for this design pattern, would both ArcadePlayer and ArcadeGame need to cast the passed ArcadeScreen and ArcadeMove to a narrower class respectively? Is there any need to pass typing information between the two classes or to the mediator? Thank you for introducing me to the pattern, it was something I heard about before but did not look further into.
    – Alex
    Commented May 12, 2019 at 23:31
  • They shouldn't need to do any casting. ArcadeScreen should be an interface/abstract base class that defines all the operations you would need. If you find that you need to cast that class to something more specific, you should review your design. It's also possible that the Mediator pattern isn't appropriate for your actual use case.
    – Matthew
    Commented May 13, 2019 at 11:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.