The Factory Method Design Pattern

December 10th, 2021

⏱ Reading Time: 7 mins

The purpose of design patterns is to outline solutions to various common software design problems. Becoming popular by the Gang of Four, design patterns provide a theoretical approach on how to solve common challenges that software engineers meet on a daily basis. They do not constitute specific code implementations, therefore they can be adopted and implemented appropriately in many programming languages. Design patterns are separated in three general categories; creational, structural and behavioral. In this post I’m presenting the factory method, a creational design pattern.

Suppose that you run a tire shop and you have a standard procedure to install tires on car wheels. One day you realize that there is high demand from customers to install tires on trucks as well. And after a while you are called to do the same on motorcycles. In order to cover these new demands, you add two new procedures so you can adapt and serve the new vehicle types respectively. And right when you have put all new stuff in motion, there it comes the need to introduce a fourth procedure in order to work with bicycles as well.

Let’s say that the tire installation procedure on each vehicle type can be represented programmatically by a class. The client code, the one that is responsible to order the initiation of the actual installation job, must mandatorily know which class to use depending on the vehicle it has to serve; it must be able to create instances of each class, but most importantly, to use each one’s individual APIs in order to make the whole thing work.

At first glance, this might not look so bad. Yet, there is a great downside in having the client dependent on other entities at that level of detail. The client becomes tightly coupled to each class that installs tires, and that’s an undesired situation for some good reasons:

  • It is unavoidable for the client to be mandatorily aware of several different APIs implemented in various classes, so it can initiate and go through the tire installation process. As a result, this makes client’s code more complicated both to implement and maintain.
  • Supporting new vehicles would be introducing new classes, and therefore more APIs for the client to make use of. And of course, such a thing would require changes and additions to client’s codebase as well.
  • Similarly, in case that a class changes its providing APIs or it gets deprecated, the client’s code should be updated accordingly.

As you understand, it’s easy to end up with messed up code which the more it grows, the harder it becomes to maintain. In scenarios like the above, the factory method design pattern can really help in order to break the direct connection between entities that I just described right above, and turn things into a more robust, safe, simple and maintainable direction. How?

Let’s find that out by trying to apply what the factory method pattern suggests. Simply put:

The factory method pattern describes how to have an object (client) that can be using instances of other types (other objects) without initializing them directly. Such an object does not know anything about the specific types of the other objects it’s using, and the factory method is responsible to initialize and hand them off to the former one. Factory method is defined in an interface that’s adopted by factory classes; each one provides an implementation of the factory method, where the objects that the client needs to use are being created.

You will be discovering all that step by step along the way.

Implementing the factory method design pattern

At first, it’s necessary to define an interface which conceptually will refer to the tire installation task. We’ll be calling it the Service.

Note: Another common and general name that we find in several texts is Product. As long as you are eventually able to distinguish the concepts presented here, naming is not important. After all, naming is always good to be in accordance to the general context where the pattern is being applied to.

Given that we are using Swift, we are going to implement Service as a protocol. Alternatively, it could also be a class, which the types I’m presenting next should inherit from.

Service may define properties or methods that should be common to all types that will adopt it. It may also provide default implementations of those methods in an extension. But in order to keep things simple here, I’ll just leave it empty.

Now, we are going to implement a few concrete types (classes) of the Service protocol. Each one will be matching to an actual tire installation task, and that way we manage to make the general concept specific:

What a client code actually needs is to initialize instances of the above classes, depending on the vehicle type. However, here it comes the crucial moment. Instead of letting a client code to be creating instances of the above classes directly, we will introduce an intermediate layer. It will be living between the previous types and the client presented next.

That layer is going to consist of another protocol (another interface, which could also be a class of course), and a set of concrete types (classes) that will be conforming to it. The protocol should be specifying at least one method; that is the factory method:

Regarding the concrete types, each one must be necessarily doing three things:

  • To be conforming to the Factory protocol.
  • To be implementing the installTires() method required by the Factory protocol.
  • To be initializing and returning a Service type instance from the installTires() method.

Note that each class will be creating an instance of a specific Service type. This fact borns the requirement to implement as many classes as the ones conforming to Service protocol; it has to be a one-to-one matching.

In code, the above is translated into this:

Time to implement a small client to try all the above out. For convenience, vehicle types will be specified as cases in an Enum type inside the client’s class right below. A custom method initiates the tire installation process for any given vehicle:

See that the TireShop class (the client) does not contain any property of a concrete Service type, so coupling has been totally avoided! TireShop has no idea what Service types exist, or which one is responsible to serve each vehicle type. Instead, all it knows is that depending on the given vehicle it just has to initialize the respective Factory type, and then to call one method; installTires(). That’s the only API it has to deal with!

The service property in the above example is probably looking unnecessary at first glance. However, in actual scenarios it can be used in order to call properties or methods defined in the Service protocol.

Putting TireShop in action after having done all the above results to the following:

A more realistic example

In favor of the demonstration, let’s assume that we want to follow the factory method pattern in order to implement a mechanism that will be returning random values of three specific types; string, double and integers.

Let’s start with the first interface, the one that we called Service in the previous example. This time we will call it RandomValue:

See that we declare a property called value, which is of AnyHashable type. This property will be containing an actual random value (int, double or string) which will be getting in the RandomValue concrete types.

We want to be able to produce three different kinds of random values, so let’s implement the next three simple classes:

The UUID class is a handy way to generate unique string values in the StringRandomValue class. For double values in the DoubleRandomValue class, the timeIntervalSinceReferenceDate static property of the Date type will be always returning a unique TimeInterval value, which is actually a double number. As for integers, using the random(in:) method in a range of integer numbers is sufficient for this example in the IntRandomValue type.

The first part that does the real job is ready. Let’s create now the second interface that we need (factory), along with a few concrete types too. The RandomValueFactory protocol shown next specifies the factory method for this example, called generateRandomValue(); it returns a RandomValue instance. Through that, we’ll be able to access the value property and get the actual random value generated by the various Service types.

There will be three concrete types that will be conforming to the RandomValueFactory protocol. Each one will be initializing and returning an instance of a matching RandomValue type presented above:

In the client class of all the above that is implemented next, see that we call the generateRandomValue() method from the generator; a RandomValueFactory object. Since it returns a RandomValue instance, we access the value property in order to get the desirable random value directly.

Using the Client is shown right next:

See that once again the Client class does not know anything about the underlying mechanism that generates the random numbers, nor it is coupled in any way with any RandomValue types.

Conclusion

As you found out in the above two examples, following the factory method design pattern guidelines can be proved pretty helpful in order to separate concepts and concerns. To sum up, we always need to implement two interfaces (preferably protocols) along with concrete  types; the first set will be doing the actual job, the other will be the one residing between the former and the client code. In general, the factory method pattern makes testing easier, it allows to perform additions or modifications without causing tons of changes in the codebase, and at the same time it minimizes the risk to break properly working functionalities. Try to follow it in your own programming tasks when fits, and you will definitely not lose. I hope you enjoyed and found this post useful.

Thank you for reading, take care! ????

Stay Up To Date

Subscribe to my newsletter and get notifiied instantly when I post something new on SerialCoder.dev.

    We respect your privacy. Unsubscribe at any time.