Factory (method)
The Factory design pattern is one of the most important design patterns which allows higher abstraction when creating a class instance than a classical constructor. Typically, it's used to encapsulate more complex instance initialization and to create different instance types based on a string.
Motivation
In applications, it sometimes happens that we need to create an instance of a class and initialize it further more. Form components are a good practical example where creating an instance is not just enough, but we also need to set many other properties (dimensions, caption, position, color...). If you create 20 similar buttons somewhere in your application and it takes 10 lines to create each button, you might consider separating the code into a method. Congratulations, you have just invented the factory (of course, the pattern has some more formalities).
The factory can also store variables needed to create the instances. Like this, these variables don't need to be passed through the entire application. Another advantage is the return type which doesn't have to be exactly the type of the instance we're creating. We can return one of the parent classes or even an interface. We'll take a closer look at each of these cases.
The Factory design pattern comes in different forms and there are also its other variations (Factory, Abstract Factory, Factory Method, Simple Factory) and various sources usually interpret them differently. However, the core idea is always the same.
Factory Method
The Factory Method design pattern uses a method calling the constructor. It comes in many different forms, sometimes it can use inheritance and it's mostly written against an interface. We'll show the simplest implementation here. The key principle is to separate the construction of a particular instance into another class, which prevents polluting the original class with construction code.
class Car { private string maker; private string model; public Car(string maker, string model) { this.maker = maker; this.model = model; } } class CarFactory { public Car CreateFocus() { return new Car("Ford", "Focus"); } }
We have a simple class with a public constructor here. We can create specific car instances as:
Car mondeo = new Car("Ford", "Mondeo");
Because we often create Focus cars in our application or they are simply more
important for us and at the same time, we don't want to interfere with
the Car
class, we can simplify their construction to just
calling a factory class method:
CarFactory factory = new CarFactory();
Car focus = factory.CreateFocus();
If you imagine that Focus has e.g. 30 attributes initialized automatically now, the pattern will definitely pay off. And even if we needed Focus just in one place in our application, moving a complex initialization into another class clarifies the logic in the class using this instance.
Factory
The Factory design pattern is more general. Basically, it's like the Factory Method, because, again, it's a method which creates our instance. However, the requirements are much less strict here. The method can be declared as static (sometimes even in the same class, as we can typically see in Java). Here's another example:
class Car { private string maker; private string model; private Car(string maker, string model) { this.model = model; this.maker = maker; } public static Car Focus() { return new Car("Ford", "Focus"); } }
In this variant of the pattern, a class instance can't be created in any other way than by the factory method (but of course, the constructor can be public as well).
We create an instance as:
Car focus = Car.Focus();
The simpler implementation is the advantage of a static method right in the class. Of course, we shouldn't have too many of them in the class and they should be somehow bound to the original class' functionality. Otherwise, they should be in a separate class. Perhaps the best example of such a static method is getting the current date and time in C# .NET:
DateTime november = new DateTime(2018, 11, 24); // Specific date DateTime today = DateTime.Now();
The Now()
method returns a DateTime
instance
initialized to the current date and time. Such a method is directly related to
the DateTime
functionality and therefore it's a correct design it's
in this class and it even makes sense it's static. On the other hand, with our
Focus()
, it's rather a deterrent example, since it doesn't have
much to do with the general Car
class.
Note: In C# .NET, Now()
is actually a property that differs
from a method in some details. In the example above, it's been shown as a method
to avoid confusing programmers using other languages.
Creating instances of different classes
The return value of the Factory method doesn't have to be
the same as the type of the instance being created. We can easily create an
instance of a different class on each call and return only the interface that
all the classes implement. As an example, we'll show a drawing program that
renders different shapes on the screen. So, let's say we have a square, a
circle, and a triangle, all of them implementing the IDrawable
interface. We get the data from a string (for example, we're parsing a text
file). According to the data provided, we decide which shape to create and
return it only as an interface. The program itself doesn't know what the shape
is. It just knows it can render it.
interface IDrawable { void Draw(); } class Square : IDrawable { /* ... code ... */ } class Triangle : IDrawable { /* ... code ... */ } class Circle : IDrawable { /* ... code ... */ } class ShapeFactory { public IDrawable Create(string type) { if (type == "Square") return new Square(); else if (type == "Triangle") return new Triangle(); else if (type == "Circle") return new Circle(); } } // usage in the program Factory factory = new ShapeFactory(); IDrawable instance = factory.Create("Square");
We can see the type is changing. The only thing the program knows is that the object can be rendered but not how to render it. It even shouldn't be its concern because it doesn't care take care of the rendering. The rendering is either a concern of a concrete class or of the objects themselves.
If we had more shapes, it'd be more useful to use reflection and create class instances dynamically based on the shape name. We must not forget to restrict the classes being instanciated to a concrete package somehow. Otherwise, the user could create pretty much anything from our application.
Parameter dependencies
Sometimes we need to create a class instance, but we retrieve parameters for the constructor somewhere else in the application. We can't call the constructor since we don't have all the parameters yet and creating an uninitialized instance by e.g. a non-parametric constructor is not a good practice. If we use the Factory class, we can pass data to it gradually and it'll store them. Once there's enough data, we can create an instance. This way we don't have to worry about passing any data between the parts of the program, we only pass the Factory class instance.
Further implementations of different factory types will be added to this article. Would you like to help us with your experience with the factory? Write us a comment.