Where are objects composed?

Ok, we went through some ways of passing a recipient to a sender. We did it from the “internal” perspective of a sender that is given a recipient. What we left out, for the most part, is the “external” perspective, i.e. who should pass the recipient into the sender?

For almost all of the approaches described in the previous chapter, there is no limitation – you pass the recipient from where you need to pass it.

There is one approach, however, that is more limited, and this approach is passing as a constructor parameter.

Why is that? Because, we are trying to be true to the principle of “separating objects creation from use” and this, in turn, is a result of us striving for composability.

Anyway, if an object cannot both use and create another object, we have to make special objects just for creating other objects (there are some design patterns for how to design such objects, but the most popular and useful is a factory) or defer the creation up to the application entry point (there is also a pattern for this, called composition root).

So, we have two cases to consider. I’ll start with the second one – composition root.

Composition Root

let’s assume, just for fun, that we are creating a mobile game where a player has to defend a castle. This game has two levels. Each level has a castle to defend. When we manage to defend the castle long enough, the level is considered completed and we move to the next one. So, we can break down the domain logic into three classes: a Game that has two Levels and each of them that contains a Castle. Let’s also assume that the first two classes violate the principle of separating use from construction, i.e. that a Game creates its own levels and each Level creates its own castle.

A Game class is created in the Main() method of the application:

1 public static void Main(string[] args)
2 {
3   var game = new Game();
4 
5   game.Play();
6 }

The Game creates its own Level objects of specific classes implementing the Level interface and stores them in an array:

1 public class Game
2 {
3   private Level[] _levels = new[] {
4     new Level1(), new Level2()
5   };
6 
7   //some methods here that use the levels
8 }

And the Level implementations create their own castles and assign them to fields of interface type Castle:

 1 public class Level1
 2 {
 3   private Castle _castle = new SmallCastle();
 4 
 5   //some methods here that use the castle
 6 }
 7 
 8 public class Level2
 9 {
10   private Castle _castle = new BigCastle();
11 
12   //some methods here that use the castle
13 }

Now, I said (and I hope you see it in the code above) that the Game, Level1 and Level2 classes violate the principle of separating use from construction. We don’t like this, do we? Let’s try to make them more compliant with the principle.

Achieving separation of use from construction

First, let’s refactor the Level1 and Level2 according to the principle by moving the instantiation of their castles outside. As the existence of a castle is required for a level to make sense at all – we will say this in code by using the approach of passing a castle through a Level’s constructor:

 1 public class Level1
 2 {
 3   private Castle _castle;
 4 
 5   //now castle is received as
 6   //constructor parameter
 7   public Level1(Castle castle)
 8   {
 9     _castle = castle;
10   }
11 
12   //some methods here that use the castle
13 }
14 
15 public class Level2
16 {
17   private Castle _castle;
18 
19   //now castle is received as
20   //constructor parameter
21   public Level2(Castle castle)
22   {
23     _castle = castle;
24   }
25 
26   //some methods here that use the castle
27 }

This was easy, wasn’t it? However, it leaves us with an issue to resolve: if the instantiations of castles are not in Level1 and Level2 anymore, then they have to be passed by whoever creates the levels. In our case, this falls on the shoulders of Game class:

 1 public class Game
 2 {
 3   private Level[] _levels = new[] {
 4     //now castles are created here as well:
 5     new Level1(new SmallCastle()),
 6     new Level2(new BigCastle())
 7   };
 8 
 9   //some methods here that use the levels
10 }

But remember – this class suffers from the same violation of not separating objects use from construction as the levels did. Thus, to make this class compliant to the principle as well, we have to treat it the same as we did the level classes – move the creation of levels outside:

 1 public class Game
 2 {
 3   private Level[] _levels;
 4 
 5   //now levels are received as 
 6   //constructor parameter
 7   public Game(Level[] levels)
 8   {
 9     _levels = levels;
10   }
11 
12   //some methods here that use the levels
13 }

There, we did it, but again, the levels now must be supplied by whoever creates the Game. Where do we put them? In our case, the only choice left is the Main() method of our application, so this is exactly where we are going to create all the objects that we pass to a Game:

 1 public static void Main(string[] args)
 2 {
 3   var game =
 4     new Game(
 5       new Level[] { 
 6         new Level1(new SmallCastle()),
 7         new Level2(new BigCastle())
 8   });
 9 
10   game.Play();
11 }

By the way, the Level1 and Level2 are differed only by the castle types and this difference is no more as we refactored it out, so we can make them a single class and call it e.g. TimeSurvivalLevel (because such level is considered completed when we manage to defend our castle for a specific period). After this move, now we have:

 1 public static void Main(string[] args)
 2 {
 3   var game =
 4     new Game(
 5       new Level[] {
 6         new TimeSurvivalLevel(new SmallCastle()),
 7         new TimeSurvivalLevel(new BigCastle())
 8   });
 9 
10   game.Play();
11 }

Looking at the code above, we might come to another funny conclusion – this violates the principle of separating use from construction as well! First, we create and connect the web of objects and then send the Play() message to the game object. Can we fix this as well?

I would say “no”, for two reasons:

  1. There is no further place we can defer the creation. Sure, we could move the creation of the Game object and its dependencies into a separate object responsible only for the creation (e.g. a factory), but it would still leave us with the question: where do we create the factory? Of course, we could use a static method to call it in our Main() like this: var app = ApplicationRoot.Create(), but that would be delegating the composition, not pulling it up.
  2. The whole point of the principle we are trying to apply is decoupling, i.e. giving ourselves the ability to change one thing without having to change another. When we think of it, there is no point of decoupling the entry point of the application from the application itself, since this is the most application-specific and non-reusable part of the application we can imagine.

What I consider important is that we reached a place where the web of objects is created using the constructor approach and we have no place left to defer the creation of the web (in other words, it is as close as possible to application entry point). Such a place is called a composition root.

We say that composition root is “as close as possible” to the application entry point because there may be different frameworks in control of your application and you will not always have the Main() method at your service8.

Apart from the constructor invocations, the composition root may also contain, e.g., registrations of observers (see registration approach to passing recipients) if such observers are already known at this point. It is also responsible for disposing of all objects it created that require explicit disposal after the application finishes running. This is because it creates them and thus it is the only place in the code that can safely determine when they are not needed.

The composition root above looks quite small, but you can imagine it growing a lot in bigger applications. There are techniques of refactoring the composition root to make it more readable and cleaner – we will explore such techniques in a dedicated chapter.

Factories

Earlier, I described how it isn’t always possible to pass everything through the constructor. One of the approaches we discussed that we can use in such cases is a factory.

When we previously talked about factories, we focused on it being just a source of objects. This time we will have a much closer look at what factories are and what are their benefits.

But first, let’s look at an example of a factory emerging in code that was not using it, as a mere consequence of trying to follow the principle of separating objects use from construction.

Emerging factory – example

Consider the following code that receives a frame that came from the network (as raw data), then packs it into an object, validates and applies to the system:

 1 public class MessageInbound
 2 {
 3   //...initialization code here...
 4 
 5   public void Handle(Frame frame)
 6   {
 7     // determine the type of message
 8     // and wrap it with an object
 9     ChangeMessage change = null;
10     if(frame.Type == FrameTypes.Update)
11     {
12       change = new UpdateRequest(frame);
13     }
14     else if(frame.Type == FrameTypes.Insert)
15     {
16       change = new InsertRequest(frame);
17     }
18     else
19     {
20       throw
21         new InvalidRequestException(frame.Type);
22     }
23 
24     change.ValidateUsing(_validationRules);
25     _system.Apply(change);
26   }
27 }

Note that this code violates the principle of separating use from construction. The change is first created, depending on the frame type, and then used (validated and applied) in the same method. On the other hand, if we wanted to separate the construction of change from its use, we have to note that it is impossible to pass an instance of the ChangeMessage through the MessageInbound constructor, because this would require us to create the ChangeMessage before we create the MessageInbound. Achieving this is impossible because we can create messages only as soon as we know the frame data which the MessageInbound receives.

Thus, our choice is to make a special object that we would move the creation of new messages into. It would produce new instances when requested, hence the name factory. The factory itself can be passed through a constructor since it does not require a frame to exist – it only needs one when it is asked to create a message.

Knowing this, we can refactor the above code to the following:

 1 public class MessageInbound
 2 {
 3   private readonly
 4     MessageFactory _messageFactory;
 5   private readonly
 6     ValidationRules _validationRules;
 7   private readonly
 8     ProcessingSystem _system;
 9 
10   public MessageInbound(
11     //this is the factory:
12     MessageFactory messageFactory,
13     ValidationRules validationRules,
14     ProcessingSystem system)
15   {
16     _messageFactory = messageFactory;
17     _validationRules = validationRules;
18     _system = system;
19   }
20 
21   public void Handle(Frame frame)
22   {
23     var change = _messageFactory.CreateFrom(frame);
24     change.ValidateUsing(_validationRules);
25     _system.Apply(change);
26   }
27 }

This way we have separated message construction from its use.

By the way, note that we extracted not only a single constructor, but the whole object creation logic. It’s in the factory now:

 1 public class InboundMessageFactory
 2  : MessageFactory
 3 {
 4   ChangeMessage CreateFrom(Frame frame)
 5   {
 6     if(frame.Type == FrameTypes.Update)
 7     {
 8       return new UpdateRequest(frame);
 9     }
10     else if(frame.Type == FrameTypes.Insert)
11     {
12       return new InsertRequest(frame);
13     }
14     else
15     {
16       throw
17         new InvalidRequestException(frame.Type);
18     }
19   }
20 }

And that’s it. We have a factory now and the way we got to this point was by trying to adhere to the principle of separating use from construction.

Now that we are through with the example, we’re ready for some more general explanation on factories.

Reasons to use factories

As demonstrated in the example, factories are objects responsible for creating other objects. They are used to achieve the separation of objects construction from their use. They are useful for creating objects that live shorter than the objects that use them. Such a shorter lifespan results from not all of the context necessary to create an object being known up-front (i.e. until a user enters credentials, we would not be able to create an object representing their account). We pass the part of the context we know up-front (a so-called global context) in the factory via its constructor and supply the rest that becomes available later (the so-called local context) in a form of factory method parameters when it becomes available:

1 var factory = new Factory(globalContextKnownUpFront);
2 
3 //... some time later:
4 factory.CreateInstance(localContext);

Another case for using a factory is when we need to create a new object each time some kind of request is made (a message is received from the network or someone clicks a button):

 1 var factory = new Factory(globalContext);
 2 
 3 //...
 4 
 5 //we need a fresh instance
 6 factory.CreateInstance();
 7 
 8 //...
 9 
10 //we need another fresh instance
11 factory.CreateInstance();

In the above example, two independent instances are created, even though both are created identically (there is no local context that would differentiate them).

Both these reasons were present in our example from the last chapter:

  1. We were unable to create a ChangeMessage before knowing the actual Frame.
  2. For each Frame received, we needed to create a new ChangeMessage instance.

Simplest factory

The simplest possible example of a factory object is something along the following lines:

1 public class MyMessageFactory
2 {
3   public MyMessage CreateMyMessage()
4   {
5     return new MyMessage();
6   }
7 }

Even in this primitive shape the factory already has some value (e.g. we can make MyMessage an abstract type and return instances of its subclasses from the factory, and the only place impacted by the change is the factory itself9). More often, however, when talking about simple factories, I think about something like this:

1 //Let's assume MessageFactory
2 //and Message are interfaces
3 public class XmlMessageFactory : MessageFactory
4 {
5   public Message CreateSessionInitialization()
6   {
7     return new XmlSessionInitialization();
8   }
9 }

Note the two things that the factory in the second example has that the one in the first example did not:

  • it implements an interface (a level of indirection is introduced)
  • its CreateSessionInitialization() method declares a return type to be an interface (another level of indirection is introduced)

Thus, we introduced two additional levels of indirection. For you to be able to use factories effectively, I need you to understand why and how these levels of indirection are useful, especially when I talk with people, they often do not understand the benefits of using factories, “because we already have the new operator to create objects”. The point is, by hiding (encapsulating) certain information, we achieve more flexibility:

Factories allow creating objects polymorphically (encapsulation of type)

Each time we invoke a new operator, we have to put the name of a concrete type next to it:

1 new List<int>(); //OK!
2 new IList<int>(); //won't compile...

This means that whenever we change our mind and instead of using List<int>() we want to use an object of another class (e.g. SortedList<int>()), we have to either change the code to delete the old type name and put new type name or provide some kind of conditional (if-else). Both options have drawbacks:

  • changing the name of the type requires a code change in the class that calls the constructor each time we change our mind, effectively tying us to a single implementation,
  • conditionals require us to know all the possible subclasses up-front and our class lacks extensibility that we often require.

Factories allow dealing with these deficiencies. Because we get objects from a factory by invoking a method, not by saying explicitly which class we want to get instantiated, we can take advantage of polymorphism, i.e. our factory may have a method like this:

1 IList<int> CreateContainerForData() {...}

which returns any instance of a real class that implements IList<int> (say, List<int>):

1 public IList<int> /* return type is interface */ 
2 CreateContainerForData()
3 {
4   return new List<int>(); /* instance of concrete class */
5 }

Of course, it makes little sense for the return type of the factory to be a library class or interface like in the above example (rather, we use factories to create instances of our own classes), but you get the idea, right?

Anyway, it’s typical for a declared return type of a factory to be an interface or, at worst, an abstract class. This means that whoever uses the factory, it knows only that it receives an object of a class that is implementing an interface or is derived from an abstract class. But it doesn’t know exactly what concrete type it is. Thus, a factory may return objects of different types at different times, depending on some rules only it knows.

Time to look at a more realistic example of how to apply this. Let’s say we have a factory of messages like this:

 1 public class Version1ProtocolMessageFactory
 2   : MessageFactory
 3 {
 4   public Message NewInstanceFrom(MessageData rawData)
 5   {
 6     if(rawData.IsSessionInit())
 7     {
 8       return new SessionInit(rawData);
 9     }
10     else if(rawData.IsSessionEnd())
11     {
12       return new SessionEnd(rawData);
13     }
14     else if(rawData.IsSessionPayload())
15     {
16       return new SessionPayload(rawData);
17     }
18     else
19     {
20       throw new UnknownMessageException(rawData);
21     }
22   }
23 }

The factory can create many different types of messages depending on what is inside the raw data, but from the perspective of the user of the factory, this is irrelevant. All that it knows is that it gets a Message, thus, it (and the rest of the code operating on messages in the whole application for that matter) can be written as general-purpose logic, containing no “special cases” dependent on the type of message:

1 var message = _messageFactory.NewInstanceFrom(rawData);
2 message.ValidateUsing(_primitiveValidations);
3 message.ApplyTo(_sessions);

Note that this code doesn’t need to change in case we want to add a new type of message that’s compatible with the existing flow of processing messages10. The only place we need to modify in such a case is the factory. For example, imagine we decided to add a session refresh message. The modified factory would look like this:

 1 public class Version1ProtocolMessageFactory
 2   : MessageFactory
 3 {
 4   public Message NewInstanceFrom(MessageData rawData)
 5   {
 6     if(rawData.IsSessionInit())
 7     {
 8       return new SessionInit(rawData);
 9     }
10     else if(rawData.IsSessionEnd())
11     {
12       return new SessionEnd(rawData);
13     }
14     else if(rawData.IsSessionPayload())
15     {
16       return new SessionPayload(rawData);
17     }
18     else if(rawData.IsSessionRefresh())
19     {
20       //new message type!
21       return new SessionRefresh(rawData);
22     }
23     else
24     {
25       throw new UnknownMessageException(rawData);
26     }
27   }
28 }

and the rest of the code could remain untouched.

Using the factory to hide the real type of message returned makes maintaining the code easier, because there are fewer places in the code impacted by adding new types of messages to the system or removing existing ones (in our example – in case when we do not need to initiate a session anymore) 11 – the factory hides that and the rest of the application is coded against the general scenario.

The above example demonstrated how a factory can hide that many classes can play the same role (i.e. different messages could play the role of a Message), but we can as well use factories to hide that the same class plays many roles. An object of the same class can be returned from different factory method, each time as a different interface and clients cannot access the methods it implements from other interfaces.

Factories are themselves polymorphic (encapsulation of rule)

Another benefit of factories over inline constructor calls is that if a factory is received an object that can be passed as an interface, which allows us to use another factory that implements the same interface in its place via polymorphism. This allows replacing the rule used to create objects with another one, by replacing one factory implementation with another.

Let’s get back to the example from the previous section, where we had a Version1ProtocolMessageFactory that could create different kinds of messages based on some flags being set on raw data (e.g. IsSessionInit(), IsSessionEnd() etc.). Imagine we decided we don’t like this version anymore. The reason is that having so many separate boolean flags is too cumbersome, as with such a design, we risk receiving a message where two or more flags are set to true (e.g. someone might send a message that indicates that it’s both a session initialization and a session end). Supporting such cases (e.g. by validating and rejecting such messages) requires additional effort in the code. We want to make it better before more customers start using the protocol. Thus, a new version of the protocol is conceived – a version 2. This version, instead of using several flags, uses an enum (called MessageTypes) to specify the message type:

1 public enum MessageTypes
2 {
3   SessionInit,
4   SessionEnd,
5   SessionPayload,
6   SessionRefresh
7 }

thus, instead of querying different flags, version 2 allows querying a single value that defines the message type.

Unfortunately, to sustain backward compatibility with some clients, both versions of the protocol need to be supported, each version hosted on a separate endpoint. The idea is that when all clients migrate to the new version, the old one will be retired.

Before introducing version 2, the composition root had code that looked like this:

1 var controller = new MessagingApi(new Version1ProtocolMessageFactory());
2 //...
3 controller.HostApi(); //start listening to messages

where MessagingApi has a constructor accepting the MessageFactory interface:

1 public MessagingApi(MessageFactory messageFactory)
2 {
3   _messageFactory = messageFactory;
4 }

and some general message handling code:

1 var message = _messageFactory.NewInstanceFrom(rawData);
2 message.ValidateUsing(_primitiveValidations);
3 message.ApplyTo(_sessions);

This logic needs to remain the same in both versions of the protocol. How do we achieve this without duplicating this code for each version?

The solution is to create another message factory, i.e. another class implementing the MessageFactory interface. Let’s call it Version2ProtocolMessageFactory and implement it like this:

 1 //note that now it is a version 2 protocol factory
 2 public class Version2ProtocolMessageFactory
 3   : MessageFactory
 4 {
 5   public Message NewInstanceFrom(MessageData rawData)
 6   {
 7     switch(rawData.GetMessageType())
 8     {
 9       case MessageTypes.SessionInit:
10         return new SessionInit(rawData);
11       case MessageTypes.SessionEnd:
12         return new SessionEnd(rawData);
13       case MessageTypes.SessionPayload:
14         return new SessionPayload(rawData);
15       case MessageTypes.SessionRefresh:
16         return new SessionRefresh(rawData);
17       default:
18         throw new UnknownMessageException(rawData);
19     }
20   }
21 }

Note that this factory can return objects of the same classes as version 1 factory, but it makes the decision using the value obtained from GetMessageType() method instead of relying on the flags.

Having this factory enables us to create a MessagingApi instance working with either the version 1 protocol:

1 new MessagingApi(new Version1ProtocolMessageFactory());

or the version 2 protocol:

1 new MessagingApi(new Version2ProtocolMessageFactory());

and, since for the time being we need to support both versions, our composition root will have this code somewhere12:

1 var v1Controller = new MessagingApi(new Version1ProtocolMessageFactory());
2 var v2Controller = new MessagingApi(new Version2ProtocolMessageFactory());
3 //...
4 v1Controller.HostApi(); //start listening to messages
5 v2Controller.HostApi(); //start listening to messages

Note that the MessagingApi class itself did not need to change. As it depends on the MessageFactory interface, all we had to do was supplying a different factory object that made its decision differently.

This example shows something I like calling “encapsulation of rule”. The logic inside the factory is a rule on how, when and which objects to create. Thus, if we make our factory implement an interface and have other objects depend on this interface only, we will be able to switch the rules of object creation by providing another factory without having to modify these objects (as in our case where we did not need to modify the MessagingApi class).

Factories can hide some of the created object dependencies (encapsulation of global context)

Let’s consider another toy example. We have an application that, again, can process messages. One of the things that are done with those messages is saving them in a database and another is validation. The processing of the message is, like in previous examples, handled by a MessageProcessing class, which, this time, does not use any factory, but creates the messages based on the frame data itself. Let’s look at this class:

 1 public class MessageProcessing
 2 {
 3   private DataDestination _database;
 4   private ValidationRules _validation;
 5 
 6   public MessageProcessing(
 7     DataDestination database,
 8     ValidationRules validation)
 9   {
10     _database = database;
11     _validation = validation;
12   }
13 
14   public void ApplyTo(MessageData data)
15   {
16     //note this creation:
17     var message =
18       new Message(data, _database, _validation);
19 
20     message.Validate();
21     message.Persist();
22 
23     //... other actions
24   }
25 }

There is one noticeable thing about the MessageProcessing class. It depends on both DataDestination and ValidationRules interfaces but does not use them. The only thing it needs those interfaces for is to supply them as parameters to the constructor of a Message. As the number of Message constructor parameters grows, the MessageProcessing will have to change to take more parameters as well. Thus, the MessageProcessing class gets polluted by something that it does not directly need.

We can remove these dependencies from MessageProcessing by introducing a factory that would take care of creating the messages in its stead. This way, we only need to pass DataDestination and ValidationRules to the factory, because MessageProcessing never needed them for any reason other than creating messages. This factory may look like this:

 1 public class MessageFactory
 2 {
 3   private DataDestination _database;
 4   private ValidationRules _validation;
 5 
 6   public MessageFactory(
 7     DataDestination database,
 8     ValidationRules validation)
 9   {
10     _database = database;
11     _validation = validation;
12   }
13 
14   //clients only need to pass data here:
15   public Message CreateFrom(MessageData data)
16   {
17     return
18       new Message(data, _database, _validation);
19   }
20 }

Now, note that the creation of messages was moved to the factory, along with the dependencies needed for this. The MessageProcessing does not need to take these dependencies anymore, and can stay more true to its real purpose:

 1 public class MessageProcessing
 2 {
 3   private MessageFactory _factory;
 4 
 5   //now we depend on the factory only:
 6   public MessageProcessing(
 7     MessageFactory factory)
 8   {
 9     _factory = factory;
10   }
11 
12   public void ApplyTo(MessageData data)
13   {
14     //no need to pass database and validation
15     //since they already are inside the factory:
16     var message = _factory.CreateFrom(data);
17 
18     message.Validate();
19     message.Persist();
20 
21     //... other actions
22   }
23 }

So, instead of DataDestination and ValidationRules interfaces, the MessageProcessing depends only on the factory. This may not sound like a very attractive tradeoff (taking away two dependencies and introducing one), but note that whenever the MessageFactory needs another dependency that is like the existing two, the factory is all that will need to change. The MessageProcessing will remain untouched and still coupled only to the factory.

The last thing that I want to mention is that not all dependencies can be hidden inside a factory. Note that the factory still needs to receive the MessageData from whoever is asking for a Message, because the MessageData is not available when the factory is created. You may remember that I call such dependencies a local context (because it is specific to a single use of a factory and passed from where the factory creation method is called). On the other hand, what a factory accepts through its constructor can be called a global context (because it is the same throughout the factory lifetime). Using this terminology, the local context cannot be hidden from users of the factory, but the global context can. Thanks to this, the classes using the factory do not need to know about the global context and can stay cleaner, coupled to less things and more focused.

Factories can help increase readability and reveal intention (encapsulation of terminology)

Let’s assume we are writing an action-RPG game that consists of many game levels (not to be mistaken with experience levels). Players can start a new game or continue a saved game. When they choose to start a new game, they are immediately taken to the first level with an empty inventory and no skills. Otherwise, when they choose to continue an old game, they have to select a file with a saved state (then the game level, skills, and inventory are loaded from the file). Thus, we have two separate workflows in our game that end up with two different methods being invoked: OnNewGame() for a new game mode and OnContinue() for resuming a saved game:

1 public void OnNewGame()
2 {
3   //...
4 }
5 
6 public void OnContinue(PathToFile savedGameFilePath)
7 {
8   //...
9 }

In each of these methods, we have to somehow assemble a Game class instance. The constructor of Game allows composing it with a starting level, character’s inventory and a set of skills the character can use:

1 public class FantasyGame : Game
2 {
3   public FantasyGame(
4       Level startingLevel,
5       Inventory inventory,
6       Skills skills)
7   {
8   }
9 }

There is no special class for “new game” or for “resumed game” in our code. A new game is just a game starting from the first level with an empty inventory and no skills:

1 var newGame = new FantasyGame(
2   new FirstLevel(),
3   new BackpackInventory(),
4   new KnightSkills());

In other words, the “new game” concept is expressed by a composition of objects rather than by a single class, called e.g. NewGame.

Likewise, when we want to create a game object representing a resumed game, we do it like this:

 1 try
 2 {
 3   saveFile.Open();
 4 
 5   var loadedGame = new FantasyGame(
 6     saveFile.LoadLevel(),
 7     saveFile.LoadInventory(),
 8     saveFile.LoadSkills());
 9 }
10 finally
11 {
12   saveFile.Close();
13 }

Again, the concept of “resumed game” is represented by a composition rather than a single class, just like in the case of “new game”. On the other hand, the concepts of “new game” and “resumed game” are part of the domain, so we must make them explicit somehow or we lose readability.

One of the ways to do this is to use a factory13. We can create such a factory and put inside two methods: one for creating a new game, another for creating a resumed game. The code of the factory could look like this:

 1 public class FantasyGameFactory : GameFactory
 2 {
 3   public Game NewGame()
 4   {
 5     return new FantasyGame(
 6       new FirstLevel(),
 7       new BackpackInventory(),
 8       new KnightSkills());
 9   }
10 
11   public Game GameSavedIn(PathToFile savedGameFilePath)
12   {
13     var saveFile = new SaveFile(savedGameFilePath);
14     try
15     {
16       saveFile.Open();
17 
18       var loadedGame = new FantasyGame(
19         saveFile.LoadLevel(),
20         saveFile.LoadInventory(),
21         saveFile.LoadSkills());
22 
23       return loadedGame;
24     }
25     finally
26     {
27       saveFile.Close();
28     }
29   }
30 }

Now we can use the factory in the place where we are notified of the user choice. Remember? This was the place:

1 public void OnNewGame()
2 {
3   //...
4 }
5 
6 public void OnContinue(PathToFile savedGameFilePath)
7 {
8   //...
9 }

When we fill the method bodies with the factory usage, the code ends up like this:

 1 public void OnNewGame()
 2 {
 3   var game = _gameFactory.NewGame();
 4   game.Start();
 5 }
 6 
 7 public void OnContinue(PathToFile savedGameFilePath)
 8 {
 9   var game = _gameFactory.GameSavedIn(savedGameFilePath);
10   game.Start();
11 }

Note that using a factory helps in making the code more readable and intention-revealing. Instead of using a nameless set of connected objects, the two methods shown above ask using terminology from the domain (explicitly requesting either NewGame() or GameSavedIn(path)). Thus, the domain concepts of “new game” and “resumed game” become explicit. This justifies the first part of the name I gave this section (i.e. “Factories can help increase readability and reveal intention”).

There is, however, the second part of the section name: “encapsulating terminology” which I need to explain. Here’s an explanation: note that the factory is responsible for knowing what exactly the terms “new game” and “resumed game” mean. As the meaning of the terms is encapsulated in the factory, we can change this meaning throughout the application merely by changing the code inside the factory. For example, we can say that new game starts with inventory that is not empty, but contains a basic sword and a shield, by changing the NewGame() method of the factory to this:

1   public Game NewGame()
2   {
3     return new FantasyGame(
4       new FirstLevel(),
5       new BackpackInventory(
6         new BasicSword(),
7         new BasicShield()),
8       new KnightSkills());
9   }

Putting it all together, factories allow giving names to some specific object compositions to increase readability and they allow hiding the meaning of some of the domain terms for easier change in the future because we can modify the meaning of the encapsulated term by changing the code inside the factory methods.

Factories help eliminate redundancy

Redundancy in code means that at least two things need to change for the same reason in the same way14. Usually, it is understood as code duplication, but I consider “conceptual duplication” a better term. For example, the following two methods are not redundant, even though the code seems duplicated (by the way, the following is not an example of good code, just a simple illustration):

1 public int MetersToCentimeters(int value)
2 {
3   return value*100;
4 }
5 
6 public int DollarsToCents(int value)
7 {
8   return value*100;
9 }

As I said, I don’t consider this to be redundancy, because the two methods represent different concepts that would change for different reasons. Even if I was to extract “common logic” from the two methods, the only sensible name I could come up with would be something like MultiplyBy100() which, in my opinion, wouldn’t add any value at all.

Note that so far, we considered four things factories encapsulate about creating objects:

  1. Type
  2. Rule
  3. Global context
  4. Terminology

Thus, if factories didn’t exist, all these concepts would leak to surrounding classes (we saw an example when we were talking about encapsulation of global context). Now, as soon as there is more than one class that needs to create instances, these things leak to all of these classes, creating redundancy. In such a case, any change to how instances are created probably means a change to all classes needing to create those instances.

Thankfully, by having a factory – an object that takes care of creating other objects and nothing else – we can reuse the ruleset, the global context and the type-related decisions across many classes without any unnecessary overhead. All we need to do is reference the factory and ask it for an object.

There are more benefits to factories, but I hope I managed to explain why I consider them a pretty darn beneficial concept for a reasonably low cost.

Summary

In the last chapter several chapters, I tried to show you a variety of ways of composing objects together. Don’t worry if you feel overwhelmed, for the most part, just remember to follow the principle of separating use from construction and you should be fine.

The rules outlined here apply to most of the objects in our application. Wait, did I say most of? Not all? So there are exceptions? Yes, there are and we’ll talk about them shortly when I introduce value objects, but first, we need to further examine the influence composability has on our object-oriented design approach.