Code Better: Reference Containers for Change-Resistant Constructors

Proponents of dependency injection try to design classes so they can either
work autonomously or get all services they rely on handed to them through
their constructor. But even without dependency injection, the situation often
arises where certain classes need to interact with a lot of other objects.

In these cases, you often end up with very complicated constructors and
a lot of duplicate code:

Above class takes care of rendering the visual and audible representations
of a RadarBuilding in a computer game. As you can imagine,
the same references will be required by other buildings, think
TankFactoryBuilding, CommandCenterBuilding and so
on – all duplicating the fields, their assignment and the complex constructor.

So what any sane programmer would do is consolidate this code into a common
base class aptly named Renderer:

Now the code duplication is mostly taken care of, but we
added another drawback to the code instead: if at a later time you
notice that some buildings, like your FlameThrowerBuilding
and that the ParticleBeamBuildiner, need to access the
IParticleManagerService, adding this service to the root
Renderer class requires you to change the constructors for
all of the buildings you implemented so far. Not good.

The solution to this new problem is to use a reference container
which turns those references into a single object, making the building
classes resistant to change as long as the services they access are
provided for (of course, this is not an invitation to randomly add
references into the container – the principles of object oriented design
still apply!)

For the price of a base class and a container class being added to
the project, the constructors are simple once again and changing
the references provided to a renderer can be done in a single place,
without the need to edit all the renderer classes.

Needless to say that this pattern should only be applied if you have
a lot of similar objects consuming the same services. In cases where
there are only few variants required, a plain swithc statement or a set
of methods might be a better option!

I’ve used this approach before but your example seems a little odd to me because I wouldn’t think a ‘Renderer’ would need to know about the audio manager?

The approach I used is to have an IEngine interface that provides the services to the game objects. The IEngine would expose each of the subsystems like IGraphics, IPhysics, ISound, etc and then each game object just has a reference to the IEngine passed into the constructor.

In my current implementatation though I’m using a component based approach. The idea is that each game object is a collection of components and each component has one simple task to do. Some of the components derive from the EngineComponent which gives them access to the subsystems that way. While others don’t need to know anything about the engine.

I’ve seen the term “rendering” applied to audio, too. My Renderers are the glue between the logical representation of the game’s world and the audible scene (IAudioManager) as well as the visual scene (ISceneGraph). Maybe naming these things Renderers is altogether wrong – I just can’t think of a better alternative (eg. an IMaintainGameObjectRepresentationInSceneGraphAndAudioManager would be the most accurate, just not too friendly on the eyes) – so I picked the closest term and standardized its meaning to this throughout the project.

Regarding the IEngine concept, I tried to keep the dependencies down as much as possible so I could easily mock them. I think IEngine is a bit too close to the service locator anti-pattern ([1], [2], [3]) in that it tends to hide the dependencies. For example, any object in the game world could theoretically ask the IEngine for its scene graph or audio manager, thus causing a dependency that wouldn’t be there if the world is being simulated on a server without audio and graphics (I had a little run in with a such a situation: MVC in Games).

The component based approach (aka Composition over Inheritance, I believe) is something I really should move to. You’re way ahead of me there – I only learned the advantages of this design when I tried out Unity some time ago 🙂

I wonder if it’s possible to keep the pure game logic separate from the graphics/audio stuff and use a composition-based architecture. Maybe components could be classified as affectors (= collision, physics, steering, scripts: game logic relevant) and observers (= no interaction with game object, only i.e. put a model in the scene graph for the game object). But then saving/loading the world becomes more difficult (for the game this example was based on, maps and save games are one and the same, I simply save state of the entire world). Ideas ideas… 😀