In everyday C# programming, you create a constructor immediately after creating a class. This is because constructors create and initialize objects and instantiate them using the new keyword. However, many programmers believe that you must avoid the new keyword at all costs.
While the word ‘must’ is too heavy, there are times when creating a factory might be better than calling a constructor directly.
When it makes sense in your code, you could use a factory class or method instead of calling the constructor because the factory method can:
- be more flexibly named,
- return a subclass instance,
- return an existing object instead of creating a new one,
- give more control over the instantiation process.
This post explores why and when you should use a Factory class and where they might turn out to be problematic.
Why use a factory class/method instead of a constructor?
Before we move further, let’s introduce what a “factory class/method” is. It is a vague term that means different things to different developers. Developers mentioning factory class/method usually mean one of the following things:
- Static Factory – The static Factory Method is a public and static method that returns a new instance every time it is called. It can be inside the original class, but it can also be a part of the separate factory class.
- Simple Factory – A simple factory variant of a Factory Method design pattern can be defined as a tool to create or instantiate an object. It is neither a Factory Method pattern nor an Abstract Factory pattern. It is usually the same as the static factory pattern. The only difference between this and the static factory is that it is non-static.
- Factory Method Pattern – The Factory Method pattern implies that an interface should create the objects, and the subclasses should decide which class to instantiate. It separates the code dependent upon the interface of the object and the process of object creation.
If you want to see code examples for the above definitions, check out a separate article on the Factory Method pattern.
In this article, I will use the term “factory method” as an umbrella term for the above use cases. This is because the same principles when it comes to comparing them to constructors apply to all three variations.
Let’s go over some reasons why you might use a factory method instead of direct object construction.
The factory method can be more flexibly named
Constructors must have the same name as the class it is part of. However, there are cases when multiple constructors with different parameters are required. In those instances, a factory method works better as they don’t have the name restriction.
Developers prefer factories because it lets them define unique and self-explanatory names for their codes.
For example, a factory method that creates objects of type Foo could be named CreateFooWithCustomSettings()
rather than Foo()
. This makes it easier to understand what the factory method does and also makes it easier to refactor code if something related to object creation changes.
The factory method can return a subclass instance
For run-time decision-making, a factory method works better than a constructor.
Factories can have if-else or switch conditions that help in dealing with conditionals.
You can use it to create specialized subclasses or instances.
For instance, if a fast food company has different menus for breakfast, lunch, and dinner and has self-ordering software, its code needs to show the menu according to the external request.
public interface IMenu
{
string GetMenuName();
int CreateOrder();
int CreateInvoice();
}
class BreakfastMenu : IMenu
{
public string GetMenuName()
{
//return breakfast menu
}
public int CreateOrder()
{
//code here
}
public int CreateInvoice()
{
//code here
}
}
class LunchMenu : IMenu
{
public string GetMenuName()
{
//return Lunch menu
}
public int CreateOrder()
{
//code here
}
int CreateInvoice()
{
//code here
}
}
class DinnertMenu : IMenu
{
public string GetMenuName()
{
//return dinner menu
}
public int CreateOrder()
{
//code here
}
public int CreateInvoice()
{
//code here
}
}
This way, the implementation code can call the factory and make their order depending on user input:
public static class MenuFactory
{
public static IMenu GetMenuFromMealType(MealType mealType)
{
//logic to decide which menu to return
}
}
Moreover, whenever the restaurant decides to introduce a new menu card, they can simply introduce the subclass for it instead of changing the entire implementation.
The factory method can return an existing object instead of creating a new one
One of the main benefits of factory methods is that they allow you to return an existing object from a factory instead of always creating a new one. For example, if your factory method returns an array, it can return an existing array rather than instantiating and populating a new array every time.
The other way to reuse objects is to store them in the cache. The factory method can help improve performance in certain situations where creating new objects is costly, such as when you are working with large datasets.
The factory method gives more control over the instantiation process
Sometimes, the object creation is a complex code, exceptions, or multiple lines of logic. Such a situation calls for a factory method as they keep the code clean and prevent bugs.
In those cases, the factory method allows developers to put in a single place the logic on how objects are created.
Unlike the constructor, which is called automatically when an object is instantiated, the factory method must be invoked explicitly. This gives developers more control over the process of creating objects, as they can choose when and how to instantiate them.
This is especially useful when you need to create objects that are part of a larger system. For example, when you create an object that will use a database, you can use a factory method to ensure that the object is created with the correct database connection. This gives us more control over the system as a whole and helps us avoid potential errors.
Microsoft documentation also provides a guideline on constructor design:
Do minimal work in the constructor. Constructors should not do much work other than to capture the constructor parameters. The cost of any other processing should be delayed until required.
When not to use the factory method instead of direct object construction?
After reading the above advantages, it might seem to you that using factory methods is the best thing ever after sliced bread. However, the factory method complicates the code.
In reality, in 90% of the cases, you probably don’t need a factory method in your code. Simply use a constructor and pass the necessary dependencies through it.
public class AccountService
{
private IBookService _bookService;
private IEmailSender _emailSender;
public AccountService(IBookService bookService, IEmailSender emailSender)
{
_bookService = bookService;
_emailSender = emailSender;
}
}
The default approach of using the constructors follows the KISS (Keep It Simple, Stupid) engineering principle.
There are a few situations where it is better to avoid using the factory method for object construction. For example, if the object you create is relatively simple and requires no special setup or configuration, it is probably best to use the direct object construction approach.
So overall, while factory methods have many benefits and can help simplify some aspects of object construction, you should not use them blindly in all cases. When implementing factory methods, it is important to carefully consider the pros and cons of each approach and choose the solution that makes the most sense for your project’s specific needs.
Conclusion
Factory methods can replace constructors to provide structure and increase code readability.
However, they can introduce unnecessary classes and functions if not used for the correct reasons.
So, when deciding on the factory method vs constructor, ask yourself a question: Is the factory method going to make your code flexible, extendable, and cleaner? If not, don’t go for it and stick with the conventional constructors.