Learn design patterns from real projects: RigsOfRods a multi-simulation game case study.

The majority of developers have already heard about the design patterns, GOF(Gang Of Four) patterns are the most popularized, and each developer has his way to learn them , we can enumerate:

  • Reading a book.
  • From web sites.
  • From a collegue.
  • Doing a training.

Regardless of the method chose, we can learn by heart the patterns and spent hours to memorize their UML diagrams, but sometimes when we need to use them in a real project, it becomes more problematic.

What’s very important is not to know exactly the pattern names and how to implement them as described in the documentation, but what’s more relevant is the motivation behind each pattern, it’s from the motivations that we invent the patterns.

To master better the pattern motivations, an alternative way is to study them from a real project. It’s the goal of this article, we will try to explore the source code of an open source project using them heavily.

Analysis of Rigs of Rods

Rigs of Rods (“RoR”) is an open source multi-simulation game which uses soft-body physics to simulate the motion and deformation of vehicles. The game is built using a specific soft-body physics engine called Beam, which simulates a network of interconnected nodes (forming the chassis and the wheels) and gives the ability to simulate deformable objects. With this engine, vehicles and their loads flex and deform as stresses are applied. Crashing into walls or terrain can permanently deform a vehicle.

Here we go to discover some GOF design patterns used by RoR.

Singleton

The singleton is the most popular and the most used one. RoR uses a generic singleton to avoid repeating the same code for each singleton class, it defines two variants: a singleton that create new instance and another where an already created  instance is assigned.

Let’s search for all the RoR singletons, for that we can use CQLinq:

from t in Types where t.DeriveFrom(“RoRSingletonNoCreation“) || t.DeriveFrom(“RoRSingleton“)
select t

Motivation:

Let’s take the example of the InputEngine singleton, RoR needs to store data about keyboard, mouse, and joysticks, which are detected in the initialization by the InputEngine class, many classes needs the same data of the input devices, and no need to create more than one instance, so the primary motivation is to “Create one instance of InputEngine class“.

However using singleton became controversial, and not all architects and designers recommend it, here’s an article talking about the singleton controversy.

Factory Method

There is no mystery about factories, their goal is simple: Create instances, and a simple factory containing a CreateInstance method could achieve this goal. However, RoR uses the Factory Method pattern for all its factories instead of using a simple factory.

Motivation:

To understand better this pattern let’s describe the scenario where RoR uses this pattern:

  • RoR uses the graphics engine OGRE, which needs to instantiate the classes of kind ParticleEmitter.
  • RoR defines and uses its specific ParticleEmitter class named BoxEmitter which inherits from it, and wants that OGRE uses this new class as ParticleEmitter.
  • OGRE doesn’t know anything about RoR.

The question is how OGRE will know how to instantiate this new class BowEmitter from RoR and uses it? Here come the role of “Factory Method” pattern:

OGRE has an abstract class named ParticleEmitterFactory which has the CreateEmitter method, and to achieve its job , OGRE needs to a concrete factory, RoR defines a new factory BoxEmitterFactory inheriting from ParticleEmitterFactory and overloads CreateEmitter method.

RoR gives to OGRE this factory using ParticleSystemManager::addEmitterFactory (ParticleEmitterFactory * factory).  And each time OGRE needs an instance of ParticleEmitter, the BoxEmitterFactory is invoked to create it.

The most important motivation is the low coupling, indeed OGRE doesn’t know anything about RoR and it can instantiate the classes from it.

Another motivation is to enforces the cohesion, and delegate the instantiation to a specific factory class.

Using a simple factory is interesting to isolate the logic instantiation and enforces the cohesion , but using “Factory Method” is more suitable to enforces also the low coupling.

Template Method

Template method defines the skeleton of Algorithm in a method, differing some steps to subclasses. Template method lets subclasses redefine some steps of an algorithm without changing the algorithm’s structure.

The objective is to ensure that algorithm’s structure stays unchanged, while subclasses provide some part of the implementation.

Let’s use CQLinq to detect all the classes using the template method pattern, For that we can search for abstract classes ( Abstract class from the UML diagram below) where having one or more methods (templateMethod() from  the diagram) which use  some  methods implemented in  the subclass ( primitive1 and primitive2 from the diagram).

from t in Types where t.IsAbstract && t.Methods.Where(a=> a.NbLinesOfCode>0 && a.MethodsCalled.Where(b=>b.IsPureVirtual && b.ParentType==t).Count()>0).Count()>0 select t

Motivation:

Let’s take as example the IRCWrapper class,  its method “process” contains the logic of processing IRC events received, here are the methods called by it:

It invokes the pure virtual method processIRCEvent, which must be implemented by a an IRCWrapper derived class. LobbyGui is one of them and needs to treat the IRC events received, it overloads the processIRCEvent method to implements its specific behavior.

With this pattern, we can easily change the implementation of algorithms without changing the skeleton, it removes the boilerplate code and make easy the maintenance of these classes.

It also enforces the low coupling, because the client could reference only the abstract class instead of the concrete ones.

Strategy

There are common situations when classes differ only in their behavior. For this cases is a good idea to isolate the algorithms in separate classes in order to have the ability to select different algorithms at runtime.

Let’s use CQLinq to detect all classes using strategy pattern, For this purpose we can search for abstract classes, having multiple derived classes, and where the client reference the abstract class instead of the concrete implementations.

from t in Types where t.IsAbstract && t.DirectDerivedTypes.Count()>1 !t.IsThirdParty
let tt=t.DirectDerivedTypes
from db in tt where db.Methods.Where(a=>a.NbMethodsCallingMe!=0 !a.IsStatic).Count()==0
select new {db,t}

Motivation:

The camera could have multiple behaviors: fixed, free, static or isometric, and this behavior could be changed dynamically. Also, other behaviors could be added in the future.

The CameraManager uses the abstract behavior IBehavior and  here are all the methods from CameraManager  using IBehavior class.

As we can observe, there is a method named switchBehavior to change the behavior dynamically.

This pattern enforces the low coupling, Indeed, CameraManger doesn’t know the concrete behaviors, and also enforces the high cohesion, because each specific behavior is implemented in a isolated class.

State

State pattern is similar to the Strategy Design Pattern from an architectural point of view, and for this reason for the previous CQLinq request when we searched for strategy pattern, we found also state classes.

But the goal is different, the Strategy pattern represents an algorithm that uses one or more IStrategy implementations. There’s no correlation between these different behavior, however for State pattern we pass from one state to another to acheive the final objective, so there’s a cohesion between the different states.

Here are all state classes inheriting from the abstract class AppState

Like Strategy pattern, only the abstract class is referenced by the other classes, here are all the methods using AppState.

As we can observe, AppStateManager contains many methods to manage the state lifecycle.

Motivation:

Like Strategy pattern, this pattern enforces the low coupling, AppStateManger doesn’t know the concrete states and also enforces the high cohesion, because each treatment is isolated in its corresponding state.

Facade

A facade is an object that provides a simplified interface to a larger body of code, such as a class library. And to detected facades used the simple way is to search for external code used.

Here’s all namespaces used by ROR project:

let’s take as example the Caelum namespace and search for classes using it from ROR

from m in Methods where m.IsUsing (“Caelum“)
select new { m }

Only SkyManager use directly Caelum namespace, so it represent the Caelum facade.

Motivation

If we use an external library and its highly coupled with our code, i.e. many classes use directly this library, it will be very difficult to change this external library. However, if a facade is used, only its implementation will be changed if we want to change the external library.

This pattern enforces the low coupling with external libraries.

Conclusion

After learning the GOF patterns, it’s interesting  to know the motivations behind using them in your code. Discovering the implementation of patterns from known open source projects could help you to understand better the utility of the patterns.