Originally posted here
The Factory Method is a creational design pattern that allows the abstraction of object creation. It defines a method for creating an instance based on a superclass but allows subclasses to alter the type of objects that they create.
You can find the example code of this post, on GitHub
Conceptualizing the Problem
Imagine that we are working for a logistics company that hired us to create a logistics management application. The company is small and has some trucks to handle transportation. Thus our application can only transport goods via truck, and the bulk of our code lives inside the Truck
class.
Thanks to our application the company gains traction and growing exponentially. Eventually, the company buys a cargo ship and now wants us to incorporate sea logistics into the app.
That's great news, but how about the code? Currently, most of the code is coupled to the Truck
class. Adding a Ship
class into the application would require architectural-level changes to the entire codebase. Moreover, if later we need to add another type of transportation to the application, we will probably need to make all of these changes again.
As a result, we will end up with a nasty codebase, riddled with conditionals that alter the application's behaviour depending on the transportation mode.
The Factory Method pattern suggests that we should replace direct object construction calls (using the new
operator) with calls to a factory method. Objects returned by a factory method are often referred to as products.
Initially, this change does not make any sense: we just moved the constructor call from one part of the code to another. However, now we can override the factory method in a subclass and change the products being created by the method.
There's a limitation though: subclasses may be able to return different types of products, but these products must have a common base class or interface.
Back to our logistics application, both Truck
and Ship
classes must implement a common interface, for example, ITransport
, which declares a method called Deliver
. The classes can implement the interface differently: the Truck
class is concerned with cargo delivery by land, while the Ship
class is concerned with cargo delivery by sea.
The client using the factory method does not see a difference between the actual products returned by each subclass. The client treats all the products as abstract ITransport
objects. The client also knows that all ITransport
objects must implement some Deliver
method, but how each of them implements it doesn't matter.
Structuring the Factory Method Pattern
In its base implementation, the Factory Method pattern has four participants:
- Product: The Product declares an interface, which is common to all objects that can be produced by the creator and its subclasses.
- Concrete Products: Concrete Products are different implementations of the product interface.
- Creator: The Creator class declares the factory method that returns new product objects. The return type of this method must match the product interface. We can declare the factory method
abstract
to force all subclasses to implement their versions of the method. As an alternative, the base factory method can return some default product types. Note, that despite its name, product creation is not the primary responsibility of the creator. Usually, the creator class already has some core business logic related to products. The factory method helps to decouple this logic from the concrete product classes. Here is an analogy: a large software development company can have a training department for developers. However, the primary function of the company as a whole is still writing code, not producing developers. - Concrete Creators: The Content Creators override the base factory method so it returns a different type of product.
To demonstrate how the Factory Method pattern works, we are going to create...a sandwich. According to Wikipedia:
A sandwich is a food typically consisting of vegetables, sliced cheese or meat, placed on or between slices of bread, or more generally any dish wherein bread serves as a container or wrapper for another food type.
To start, we will implement some Product participants, which will be the ingredients that comprise the sandwiches. We'll create an abstract Ingredient
class to represent them:
namespace FactoryMethod.Ingredients
{
/// <summary>
/// The Product Participant
/// </summary>
public abstract class Ingredient
{
}
}
Now let's instantiate a few classes to represent ingredients in sandwiches (our CocreteProduct participants):
namespace FactoryMethod.Ingredients
{
/// <summary>
/// Concrete Product
/// </summary>
public class Bread : Ingredient
{
}
}
namespace FactoryMethod.Ingredients
{
/// <summary>
/// Concrete Product
/// </summary>
public class CornedBeef :Ingredient
{
}
}
namespace FactoryMethod.Ingredients
{
/// <summary>
/// Concrete Product
/// </summary>
public class Sauerkraut : Ingredient
{
}
}
namespace FactoryMethod.Ingredients
{
/// <summary>
/// Concrete Product
/// </summary>
public class SwissCheese : Ingredient
{
}
}
namespace FactoryMethod.Ingredients
{
/// <summary>
/// Concrete Product
/// </summary>
public class ThousandIslandsSauce:Ingredient
{
}
}
What we want to do now is to create a factory that will allow us to build different kinds of sandwiches using the same set of ingredients. What will differ between the kinds of sandwiches will be the amount and order of said ingredients.
First, let's build an abstract class Sandwich
that represents all possible kinds of sandwiches. This is the Creator participant:
using FactoryMethod.Ingredients;
namespace FactoryMethod.Sandwiches
{
/// <summary>
/// Creator
/// </summary>
public abstract class Sandwich
{
private List<Ingredient> ingredients = new List<Ingredient>();
public Sandwich()
{
CreateIngredients();
}
public abstract void CreateIngredients();
public List<Ingredient> Ingredients
{
get { return ingredients; }
}
public void DisplayIngredients()
{
foreach (var ingredient in ingredients)
Console.WriteLine(ingredient.GetType().Name);
}
}
}
Note the CreateIngredients()
method. This method is the Factory Method which gives the pattern its name. It's not implemented here because that implementation is left to the ConcreteCreator classes that we now need to define. Let's start with a Reuben sandwich:
using FactoryMethod.Ingredients;
namespace FactoryMethod.Sandwiches
{
/// <summary>
/// Concrete Creator
/// </summary>
public class ReubenSandwich : Sandwich
{
public override void CreateIngredients()
{
Ingredients.Add(new Bread());
Ingredients.Add(new CornedBeef());
Ingredients.Add(new Sauerkraut());
Ingredients.Add(new SwissCheese());
Ingredients.Add(new ThousandIslandsSauce());
Ingredients.Add(new Bread());
}
}
}
Whenever we create an object of class ReubenSandwich
, we can call CreateIngredients()
to create the correct amount and order of ingredients for this sandwich.
Let's create a GrilledCheeseSandwich
now:
using FactoryMethod.Ingredients;
namespace FactoryMethod.Sandwiches
{
public class GrilledCheeseSandwich : Sandwich
{
public override void CreateIngredients()
{
Ingredients.Add(new Bread());
Ingredients.Add(new SwissCheese());
Ingredients.Add(new Bread());
}
}
}
Now we can create the sandwich in our Main
method:
using FactoryMethod.Sandwiches;
Console.WriteLine("Reuben Sandwich");
ReubenSandwich reubenSandwich = new ReubenSandwich();
reubenSandwich.DisplayIngredients();
Console.WriteLine("\n---------------------------------\n");
Console.WriteLine("Grilled Cheese Sandwich");
GrilledCheeseSandwich grilledCheese = new GrilledCheeseSandwich();
grilledCheese.DisplayIngredients();
And as always, the output of this method will be the following:
Comparison of Different Factories
There are different references to the term Factory around the web. Though they might look as all referring to the same thing, they all have different meanings.
Let's try to figure out their differences.
Factory
The Factory is an ambiguous term that causes the most confusion. This term stands for a function method or class that is supposed to be producing something. Most commonly, factories produce objects. But they can also produce files, records to a database, logs, etc.
Any of the following can be referred to as a factory:
- A function or method that generates an application's GUI (e.g., this one)
- A class that creates users
- A static method that calls a class constructor in a certain way
- One of the creational design patterns
When someone uses the factory, the meaning of it is supposed to be clear from the context, but still causes headaches and confusion, especially in legacy codebases.
Creation Method
Joshua Kerievsky defines a Creation Method as a method that creates objects. This means that every result of a factory method pattern is a creation method but not necessarily the reverse. It also means that we can substitute the term creation method wherever Martin Fowler uses the term factory method in Refactoring.
In reality, the creation method is just a wrapper around a constructor call. It may just have a name that better expresses our intentions. On the other hand, it may help to isolate the code from changes to the constructor. It could even contain some particular business logic that would return existing objects instead of creating new ones.
A lot of people call this method a factory method just because it creates new objects. The logic is straightforward. The method creates objects and since all factories create objects, this method is a factory method. As a consequence, there's a lot of confusion between creation methods and factory methods.
The following Next
method is a creation method:
public class Number
{
private int _value;
public Number(int theValue)
{
_value = theValue;
}
public Number Next()
{
return new Number(_value + 1);
}
}
Static Creation Method
A Static Creation Method is a creation method declared as static
.
While many people call these static creation methods. That is wrong. The Factory Method is a design pattern based on inheritance. If you make it static
, you can no longer extend it via subclassing, which defeats the purpose of the pattern.
When a static creation method returns a new object, it becomes an alternative constructor.
This might be helpful when:
- We need several different constructors that have different purposes but their signatures match. For instance, having both
Random(int max)
andRandom(int min)
is impossible in Java, C++, C#, and many other languages. The most common workaround is to create several static methods that call the default constructor and set appropriate values afterwards. - We want to reuse existing objects, instead of instancing new ones (see also, the Singleton pattern). Constructors, in most programming languages, have to return new class instances. The static creation method is a workaround to this limitation. A static method can decide whether to create a fresh instance by calling the constructor or returning an existing object from some cache.
In the following example, the Load
method is a static creation method. It provides a convenient way to retrieve users from a database.
public class User {
private string id;
private string name;
private string email;
private long phoneNumber;
public User(string id,
string name,
string email,
long phoneNumber)
{
this.id = id;
this.name = name;
this.email = email;
this.phoneNumber = phoneNumber;
}
public static User Load(string id)
{
(string, string, string, long) data = Database.LoadData(id);
return new User(data.Item1, data.Item2, data.Item3, data.Item4);
}
}
Simple Factory Pattern
The Simple Factory describes a class that has a single creation method with a large conditional, that decides the product class based on the method parameters.
Simple factories are usually confused with general factories or with one of the creational design patterns. In most cases, a simple factory is an intermediate step in introducing the Factory Method or Abstract Factory patterns.
A simple factory is usually represented by a single method in a single class. Over time, this method might become too big, so we might decide to extract parts of the method into subclasses. Once we do it several times, the whole thing will turn into the classic factory method pattern.
Here's an example of a simple factory:
public class UserFactory
{
public static IUser Create(UserType type)
{
switch(type)
{
case type.User:
return new User();
case type.Customer:
return new Customer();
case type.Admin:
return new Admin();
default:
throw new ArgumentException($"Wrong user type {type}");
}
}
}
Factory Method Pattern
The Factory Method is a creational design pattern that provides an interface for creating objects but allows subclasses to alter the type of object that will be created.
If you have a creation method in the superclass and several subclasses that extend it, you probably have a factory method in your hands.
public abstract class Department
{
public abstract Employee CreateEmployee(string id);
public void Fire(string id)
{
var employee = CreateEmployee(id);
employee.PaySalary();
employee.Dismiss();
}
}
public class ITDepartment : Department
{
public Employee CreateEmployee(string id)
{
return new Programmer(id);
}
}
public class AccountingDepartment : Department
{
public Employee CreateEmployee(string id)
{
return new Accountant(id);
}
}
Abstract Factory Pattern
The Abstract Factory is a creational design pattern that allows producing families of related or dependent objects without specifying their concrete classes.
For instance the classes Transport
, Engine
and Controls
. There are might be several variants like Car
, CombustionEngine
and SteeringWheel
or Ship
, Waterjet Engine
and Helm
.
If you don't operate with product families, then you don't need an abstract factory.
A lot of people mix up the abstract factory pattern with a simple factory class declared as abstract
. Don't do that.
Pros and Cons of Factory Method Pattern
✔ We avoid tight coupling between the creator and the concrete products | ❌ The code may become more complicated since we need to introduce a lot of new subclasses to implement the pattern. The best case scenario is when we’re introducing the pattern into an existing hierarchy of creator classes. |
✔ We can move the product creation code into one place in the program, making the code easier to support, and respecting the Single Responsibility Principle | |
✔ We can introduce new types of products into the program without breaking existing client code, thus respecting the Open/Closed Principle |
Relations with Other Patterns
- Many designs start by using the Factory Method and evolve toward Abstract Factory, Prototype or Builder.
- Abstract Factory classes are often based on a set of Factory Methods.
- The Factory Method is a specialization of the Template Method. At the same time, a Factory Method may serve as a step in a large Template Method.
Final Thoughts
In this article, we have discussed what is the Factory Method pattern, when to use it and what are the pros and cons of using this design pattern. We also examined different types of factories and how the Factory Method pattern relates to other classic design patterns.
The Factory Method design pattern lets us leave the type of created object on the subclasses.
It enables us to define an interface through which the client will create the object. Its main purpose is to hide the object creation logic from the client. It is also known as a virtual constructor.
It's worth noting that the Factory Method pattern, along with the rest of the design patterns presented by the Gang of Four, is not a panacea or a be-all-end-all solution when designing an application. Once again it's up to the engineers to consider when to use a specific pattern. After all these patterns are useful when used as a precision tool, not a sledgehammer.
Top comments (0)