Design Patterns: Factory Method
Tags: beginners, programming, computerscience, architecture
Published: 2021-06-13 03:39:53

Today we will discuss about one of the most useful design patterns. 

The Factory Method

It's a creational design pattern meaning that it helps us create objects efficiently.

Efficient object creation is a regular problem, that's why **Factory Method is one of the most widely used design patterns**.

**By the end of this article, you will:**

- Understand the core concepts of Factory Method
- Recognize opportunities to use Factory Method
- Learn to create a suitable implementation of Factory Method to suit your application

## Definition

> “One advantage of static factory methods is that, unlike constructors, they have names.” ― Joshua Bloch, Effective Java

Factory Method is a creational design pattern that provides an interface to create objects to a parent-class but allows child classes to modify the type of object that will be created.

## Problem

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/90obt3wwi9bjumhxeimr.jpg)

Let's imagine that you have a shipping company. When it first started you only supported trucks.

In terms of code, it's gonna look like this:

- *Shipping class* — manages the shipping mechanism.
- *Truck class* — class that represents a truck.

```python
class Truck:
    def __init__(self, truck_id):
        self.truck_id = truck_id
        pass

    def ship(self):
        # Logic for shipping
        pass;

class Shipping:
    def __init__(self, info):
        self.truck = Truck(info["truck_id"])
        self.status = "Packaged"
        self.package = info["package"]
        pass

    def send(self):
        self.status = "Pending"
        self.truck.ship()

# Initializing a shipping mission
data = {
    "truck_id": 1,
    "package": "some_package"
}

mission = Shipping(info=data)
mission.send()
```

As you can see, the `shipping` class directly create a `truck` object, making them very coupled to one another. The `shipping` class would not work without a truck object. 

Now, imagine that your shipping company became popular and clients are wanting to ship their products overseas. So naturally, you introduce a new type of transportation, the plane. 

But, how will we be able to add that to our code?

A naive solution will be to check if the `shipping` class uses a `truck` or a `plane`.

```python
class Shipping:
    def __init__(self, info, type):
        self.type = type
        if self.type == "truck":
            self.truck = Truck(info["truck_id"])
            self.status = "Packaged"
            self.package = info["package"]
        else:
            self.plane = Plane(info["plane_id"])
            self.status = "Packaged"
            self.package = info["package"]

    def send(self):
        self.status = "Pending"
        
        if self.type == "truck":
            self.truck.ship()
        else:
            self.plane.ship()
```

This can get messy very quickly: 

- The more the types of transportation, the more conditional code we have to write.
- Due to more code, we have added complexity.
- This breaks the single responsibility principle, the `shipping` class handles shipping of many different types of transportation.
- This breaks the open-closed principle because every time we have to add a new type of transportation we have to edit existing code.
- Changing in any of the code in the `truck` or `plane` class will require changes to the `shipping` class.

Our problem here is that **we don't exactly know what types of objects we will have**, sometimes it's a truck, plane, or even a new type of transportation. 

This is what the factory method pattern fixes.

## Solution

The factory method pattern suggests that it's better to instantiate objects outside the constructor to a separate method and let subclasses control which objects get created.

So what we can do to our shipping class is:

- Remove the object instantiation from the constructor
- Make the `Shipping` class an abstract class
- Add an abstract method `setTransport` that will set the appropriate transport
- Create two new classes `TruckShipping` and `PlaneShipping` that inherit from `Shipping` class.
- Implement the `setTransport` function in the new classes.

```python
import abc # Python Library that allows us to create abstract classes

class Shipping(metaclass=abc.ABCMeta):
    
    def __init__(self, package):
        self.status = "Packaged"
        self.package = package
				self.transport = None
        
    @abc.abstractmethod
    def setTransport(self, data):
        pass

class TruckShipping(Shipping):

    def setTransport(self, id):
        self.transport = Truck(id=id)

class PlaneShipping(Shipping):

    def setTransport(self, id):
        self.transport = Plane(id=id)
```

But what about the `send` method we had in the first version of the `Shipping` class. The first version of the `send` method directly accessed the `truck` object and ran the method `ship` inside it.

Factory method pattern encourages us to create an interface or abstract class to our object types, to make them consistent and interchangeable. 

Let's do another refactor:

- Create an abstract class called `Transport` with an abstract method `ship`.
- Create two new classes that inherit from `Transport` called `Truck` and `Plane`.

```python
class Transport(metaclass=abc.ABCMeta):
    def __init__(self, id):
        self.id = id

    @abc.abstractmethod
    def ship(self):
        pass

class Truck(Transport):

    def ship(self):
        # Shipping instructions for trucks
        pass

class Plane(Transport):

    def ship(self):
        # Shipping instructions for planes
        pass
```

Finally in our Shipping abstract class, we can create a method called `send` that calls the `ship` method of a transport.

```python
def send(self):
        self.transport.ship()
```

## When to use the pattern?

Design patterns should always be used within reason, as software engineers we need to be able to detect these opportunities. 

For factory method pattern there are a couple of reasons why you might want to use it:

- When you don't know the exact types of objects your class will be interacting with. In our example, we could've had one transport system, or a hundred. You just don't know.
- Use factory method pattern when you want your users to extend the functionality of your library or framework.
- The factory method can also be used to save memory usage. Instead of creating a new object every time, you can save it in some sort of caching system.

## Pros & Cons

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pffeckaq4ur8vd8frgf3.jpg)

### Pros

- Removes tight coupling between classes.
- Increases readability.
- Allows us to construct subclasses with different properties than the parent class without using the constructor.
- Follows the single responsibility principle, making the code easier to support.
- Follows the open-closed principle, if you want to add a new type of transport, you can simply create a new subclass, without modifying existing code.
- Easier to test.

### Cons

- The code becomes more complicated because you introduced many new subclasses.

## Conclusion

Factory method is one of the most widely used design pattern, and one that you just might use next time at work!

In this article, you learned:

- What the factory method is, and it's components.
- How to refactor code, into the factory method pattern.
- Situations where factory method would be useful.
- Pros and cons of factory method

## Further Reading

If you want to learn more about the design patterns, I would recommend [Diving into Design Patterns](https://refactoring.guru/design-patterns). It explains all 23 design patterns found in the GoF book, in a fun and engaging manner. 

Another book that I recommend is [Heads First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/Head-First-Design-Patterns-Brain-Friendly/dp/0596007124), which has fun and easy-to-read explanations.