The Factory Design Pattern

The Factory Pattern is another very common pattern you will see in programming.  It is part of the Creational category of design patterns described from the Gang of Four (for more info, see my first article in this series). 

Intent & Structure

The Factory pattern gives you the ability to separate creational logic for an object to a reusable class.  The client does not need to know how the object is created.

It is just like when we purchase goods as a consumer, we usually don’t care the details of how the factory makes the product. We care that we receive the final product.

The Structure of the Strategy Pattern is comprised of:

  • The Client
    • The client needing an object to be created
  • The Factory
    • The creator of the object
  • The Product
    • The object produced by the factory
The Factory Pattern Structure – a Client/Consumer, Factory, and Product

There are also several flavors of the factory pattern:

  • Simple Factory
    • Creates objects without exposing details of instantiation
  • Factory Method
    • Define the interface for creating an object but let the subclasses decide which object to create
  • Abstract Factory
    • Provide an interface for creating a group of related or dependent objects without specifying their concrete classes

For this article, we will focus on the Simple Factory and the Factory Method.

When to Use the Factory Pattern?

When you have logic that needs to be processed in order to create an object(s) – especially when you need this logic in multiple places.  Moving this logic to a separate factory class allows you to keep your code more decoupled, makes this code reusable, therefore reducing duplicate code.

Example – Maps Application

Let’s look at an example beyond the typical “shapes” example you’ll find online – a standard Maps application on your mobile phone.  Typically, when you search for a location to get directions, you are given options for which type of transportation you would like directions for.  In my Maps app, doing a quick search between Trader Joe’s and the Empire State Building, I have these transportation types available:

  • Driving
  • Subway
  • Walking
  • Lyft
  • Biking

Let’s say you had to write the code to retrieve the transportation options to display to the user.  You could imagine that there could be different transportation available based on your location.  Not every person’s location will have a subway or Lyft available.  Maybe you don’t want to display the “walking” or “biking” option if the distance between the start and end point is over a certain distance.  There also probably could also be new ways of adding more transportation in the future. 

Example Maps Application

The “Before” Code

What’s the problem with this?

This logic is much more simplified than I’m sure what it would be in reality, but hopefully it gives you a good idea that this code can easily get complicated.  This is all within the MapClient class which would likely have all kinds of other code like needing to get the user’s current location, getting the start and end location for directions, loading the map, etc.  Having everything in a giant, monster class is generally not a good idea for maintenance long-term. 

The other thing is that transportation types available for a location could also change.  Maybe Lyft is not available today, but it could be in the future.  That means you would have to touch the code in the MapClient to update this.  Or maybe there is some new government regulation that bans biking in the city (just an example).  Having this code intermingled with the rest of the MapClient could increase your chances of breaking something when making an update. 

How to Refactor using the Factory Pattern

The Simple Factory

There are multiple ways of tackling this and I’m sure in reality Google has many microservices retrieving from databases or who knows, maybe a satellite service – but for this article example, we will look at using the Factory pattern, starting with the Simple Factory.

  • TransportFactory
    • The code related to creating the transport options list is all moved to the TransportFactory
  • MapsClient
    • The MapsClient then calls the TransportFactory to get the transport options list.

Now the MapsClient class can be free of all that extra code related to the creation of Transport options and doesn’t care how they’re created.

The Factory Method

As mentioned, over time, the number of types of transport options and logic for each one will most likely change and/or grow.  To take refactoring a step further, we could then break it up into several factories broken up by Transportation Category:

  • StandardTransportFactory
    • Car
    • Walk
    • Bike
  • ExternalTransportFactory
    • Lyft
    • Uber
  • MassTransportFactory
    • Subway
    • Bus

See the below diagram updated for the Factory Method.

Factory Method UML Diagram

The BaseTransportFactory is a new abstract class which defines the CreateTransportOptions() and the subclasses inherit from it.

The factory subclasses each implement the CreateTransportOptions() from the BaseTransportFactory with it’s own implementation. Each factory’s sole responsibility is to create Transport based on it’s type.

To be even more fancy, we can then have the MapsClient dynamically load all the factories at runtime using Reflection so we can grab transport options for each category.  This will grab all factories inheriting from our BaseTransportFactory and call CreateTransportOptions().  If we made a new factory that inherited BaseTransportFactory, it would be retrieved at runtime without having to make a change to the MapsClient.

The Benefits

We saw a lot of benefit of simply moving the transport creation code into a separate factory class.  The factory class has a single purpose of creating transport options.  The code is cleaner in the MapsClient and does not need to be updated when there is a change in transport options.

We took refactoring another step further by having a factory for each group of transportation categories – standard, external, and mass transportation.  We know that over time, the types of transport could grow and/or change.  Rather than having one giant transport factory be updated, only the specific factory needs to be updated.