The Factory method is a creational design pattern that provides an interface for creating objects without specifying their concrete classes. It defines a method that we can use to create an object instead of using its constructor. The important thing is that the subclasses can override this method and create objects of different types.
In this article, we are going to show you how to implement a Factory method design pattern. Furthermore, we are going to learn how to use the Factory method refactoring technique to hide the constructor and use our own method to expose it.
We are going to start with the simple factory implementation, and we’re gradually going to improve to achieve a very usable, but readable factory for our objects.
For the main page of this series check out C# Design Patterns.
VIDEO: Factory Design Pattern in C#.
Factory Method Implementation
To implement a Factory method pattern, we are going to create a simple Air conditioner application. Our app will receive an input from a user and based on that input will trigger a required action (cooling or warming the room). So let’s start with an interface:
public interface IAirConditioner { void Operate(); }
Now, we need concrete classes to implement this interface:
public class CoolingManager : IAirConditioner { private readonly double _temperature; public CoolingManager(double temperature) { _temperature = temperature; } public void Operate() { Console.WriteLine($"Cooling the room to the required temperature of {_temperature} degrees"); } }
public class WarmingManager : IAirConditioner { private readonly double _temperature; public WarmingManager(double temperature) { _temperature = temperature; } public void Operate() { Console.WriteLine($"Warming the room to the required temperature of {_temperature} degrees."); } }
Great. We have prepared our base functionality. Now let’s create a factory creator for these objects.
Factory Classes
We are going to start with the AirConditionerFactory
abstract class:
public abstract class AirConditionerFactory { public abstract IAirConditioner Create(double temperature); }
This abstract class provides an interface for object creation in derived classes. That being said, let’s implement our concrete creator classes:
public class CoolingFactory : AirConditionerFactory { public override IAirConditioner Create(double temperature) => new CoolingManager(temperature); }
public class WarmingFactory : AirConditionerFactory { public override IAirConditioner Create(double temperature) => new WarmingManager(temperature); }
Excellent. Now we are ready to start using our Factory methods. In many examples, we can see the switch statement which switches through the user’s input and selects the required factory class.
That works just fine.
But imagine if we have a lot of factory classes, which is quite common in large projects. That would lead to a quite big switch case statement which is quite unreadable. Therefore, we are going to use another approach.
Factory Execution
Let’s start with a simple enumeration to define air conditioner actions:
public enum Actions { Cooling, Warming }
To continue on, we are going to create the AirConditioner
class where the user can specify the type of action and execute the appropriate factory. Our concrete factories inherit from the abstract class and we are going to use that structure in our further implementation:
public class AirConditioner { private readonly Dictionary<Actions, AirConditionerFactory> _factories; public AirConditioner() { _factories = new Dictionary<Actions, AirConditionerFactory> { { Actions.Cooling, new CoolingFactory() }, { Actions.Warming, new WarmingFactory() } }; } }
This is a better way of implementing our factory execution than using a switch-case statement. But we can do it in another more dynamic way, where we don’t have to manually add action and factory creator for each action. Let’s introduce reflection into our project:
public class AirConditioner { private readonly Dictionary<Actions, AirConditionerFactory> _factories; public AirConditioner() { _factories = new Dictionary<Actions, AirConditionerFactory>(); foreach (Actions action in Enum.GetValues(typeof(Actions))) { var factory = (AirConditionerFactory)Activator.CreateInstance(Type.GetType("FactoryMethod." + Enum.GetName(typeof(Actions), action) + "Factory")); _factories.Add(action, factory); } } }
Whether we choose the first or the second example, the result should be the same:
There is one more thing we need to add to this class. And that is the method which is going to execute appropriate creation:
public class AirConditioner { //previous constructor code public IAirConditioner ExecuteCreation(Actions action, double temperature) =>_factories[action].Create(temperature); }
Now, we just have to make a call from a client. In a real-world project, we would surely check first for the current temp and then just have a factory to decide whether we should lower it or make it higher. But for sake of simplicity, we are just going to make a simple call towards our AirConditioner class:
class Program { static void Main(string[] args) { var factory = new AirConditioner().ExecuteCreation(Actions.Cooling, 22.5); factory.Operate(); } }
Our result should be as expected:
Using the Factory Method Refactoring Technique
We can use the Factory method to replace our constructor while creating an object. If our constructor consists of lots of code, we should replace it with the factory method. Furthermore, we can have multiple factory methods with meaningful names and parameter names as well which replace a single constructor.
This improves code readability a lot.
Finally, it helps us to implement a chaining syntax.
So let’s modify the AirConditioner
class with the factory method:
public class AirConditioner { private readonly Dictionary<Actions, AirConditionerFactory> _factories; private AirConditioner() { _factories = new Dictionary<Actions, AirConditionerFactory>(); foreach (Actions action in Enum.GetValues(typeof(Actions))) { var factory = (AirConditionerFactory)Activator.CreateInstance(Type.GetType("FactoryMethod." + Enum.GetName(typeof(Actions), action) + "Factory")); _factories.Add(action, factory); } } public static AirConditioner InitializeFactories() => new AirConditioner(); public IAirConditioner ExecuteCreation(Actions action, double temperature) =>_factories[action].Create(temperature); }
Our client call should be modified as well:
class Program { static void Main(string[] args) { AirConditioner .InitializeFactories() .ExecuteCreation(Actions.Cooling, 22.5) .Operate(); } }
Excellent. The result should be the same, but now we are using the factory method refactoring technique.
Conclusion
By reading this article, we have learned:
- How to implement the Factory Method design pattern into the application
- Several ways of replacing switch-case statements by using a dictionary or reflection
- How to refactor your code by using the Factory Method Refactoring Technique