Design Patterns are one of the most important aspects of software design and architecture. In this blog post, we are going to discuss the “Factory Method Pattern” and see how to implement the same in the C# programming language. The Factory Method Pattern is used to instantiate an object and falls in the Creational Pattern category as defined by the Gang of Four (GoF). If you are new to design patterns, I would highly recommend you to read the “Introduction to Design Patterns” article.
What is Factory Method Pattern
The Factory Pattern is a creational pattern that defines an interface to instantiate a class but does not specify which implemented class will be instantiated and let the process defer until application runtime. Therefore, this pattern relies on class hierarchy and all the classes must either implement an interface or inherit from an abstract class. This hierarchy abstraction help to hides the object creation logic.
Factory Method UML
Below given is a simple Factory Method UML, that represents the pattern implementation.
The sample UML consists of three major parts, the Client class, the Factory class and three concrete types that implement an ISupervisedAlgorithm interface. Let us look at what each of them does.
Client: The client class is the one who wants to use some concrete class that derives from the ISupervisedAlgorithm interface. So it requests the Factory class create method along with the name of the concrete type it wants to use and expects the Factory class to return the request instance. It does not know how this instance will get created, it just expects the Factory class to return the same.
Factory: The factory class implements the Factory Method Pattern and exposes a create method that returns the ISupervisedAlgorithm type. It hides all the complexity of creating the ISupervisedAlgorithm concrete type instance and just returns the requested object by its service user (the client class).
ISupervisedAlgorithm: This is the interface that exposes a method called predict() which returns an int value and is implemented by three concrete types i.e. NearestNeighbor, DecisionTrees, and NeuralNetworks.
Factory Method Usecases
- The Factory Method Pattern is best applicable when it is not known until runtime what class instances and dependencies are required for the code to work.
- The pattern can be used when a loose coupling is needed between the object creator and the object user.
- Another use case where the pattern can be used is when reusing an existing object is required instead of creating a new one. Here the existing object can represent objects like database connection, file systems, network resources, et, basically the resources that are costly to create.
Advantages of the Factory Method Pattern
- The Factory Method Pattern helps to avoid tight coupling between the object creator and the object user. The user did not have to instantiate the object by itself, it asks the Factory (object creator) for the required instances and simply focuses on its implementation.
- The pattern allows us to introduce new concrete types without disrupting current client class implementation thus allowing the class to extend the functionality as needed.
Disadvantages of the Factory Method Pattern
- The pattern works on abstraction and it requires a newer subclass for every concrete type to be implemented which in turn introduces unnecessary code complexity.
- The Factory Method pattern is applicable to a family of classes.
Factory Method Implementation in C#
To implement the Factory Method Pattern, let us create a C# representation for the above given UML. Here we are going to implement a simple C# console application that uses a specific machine learning supervised algorithm to perform some prediction. Let us start with the ISupervisedAlgorithm that three concrete classes will implement.
ISupervisedAlgorithm.cs: This is the contract that every concrete class implements and declares a single Predict method that every concrete class needs to provides its implementation. Please note the concrete classes returns a hard-coded integer value, this is only for explanation purposes.
public interface ISupervisedAlgorithm { int Predict(); }
DecisionTrees.cs: This is the first concrete class that implements the ISupervisedAlgorithm interface.
public class DecisionTrees : ISupervisedAlgorithm { public int Predict() { return 1; } }
NearestNeighbor.cs: This is the second concrete class that implements the ISupervisedAlgorithm interface.
public class NearestNeighbor : ISupervisedAlgorithm { public int Predict() { return 4; } }
NeuralNetworks.cs: This is the third concrete class that implements the ISupervisedAlgorithm interface.
public class NeuralNetworks : ISupervisedAlgorithm { public int Predict() { return 2; } }
SupervisedAlgorithmFactory.cs: This is the Factory class that creates and returns the object to the Client. Below given is a simple illustration of the Factory Method pattern. The implementation can also be done using Interfaces, Abstract classes, but here we will keep it simple for understanding purposes. The most important thing to note is that this class hides the object instantiation logic from its users.
The class exposes a public method called GetAlgorithm accepting the name of the algorithm the user wants the instance of.
public class SupervisedAlgorithmFactory { public static ISupervisedAlgorithm GetAlgorithm(string name) { ISupervisedAlgorithm algorithm; if (name.Equals("DecisionTrees")) { algorithm = new DecisionTrees(); } else if (name.Equals("NearestNeighbor")) { algorithm = new NearestNeighbor(); } else if (name.Equals("NeuralNetworks")) { algorithm = new NeuralNetworks(); } else { throw new ArgumentException("Invalid Algorithm Expected"); } return algorithm; } }
Client.cs: This is the client class and consumes SupervisedAlgorithmFactory class, it invokes the GetAlgorithm method by providing the name of the algorithm it wants to use and proceeds with its business logic. The client does not care how the requested object will be instantiated and rely completely on the Factory class.
public class Client { static void Main(string[] args) { var algorithm = SupervisedAlgorithmFactory.GetAlgorithm("NearestNeighbor"); Console.WriteLine($"The value predicted by NearestNeighbor: {algorithm.Predict()}"); algorithm = SupervisedAlgorithmFactory.GetAlgorithm("NeuralNetworks"); Console.WriteLine($"The value predicted by NeuralNetworks: {algorithm.Predict()}"); algorithm = SupervisedAlgorithmFactory.GetAlgorithm("DecisionTrees"); Console.WriteLine($"The value predicted by DecisionTrees: {algorithm.Predict()}"); } }
Program output:
The value predicted by NearestNeighbor: 4 The value predicted by NeuralNetworks: 5 The value predicted by DecisionTrees: 1
I hope that post gives you an idea about the Factory Method Pattern and you found this post helpful. Thanks for visiting, Cheers!!!
[Further Readings: Singleton Design Pattern in C# | Introduction to Design Patterns | Microsoft C# Version History | Microsoft .NET Core Versions History | Microsoft .NET Framework Version History | Introduction to WPF in .NET Core | Useful Visual Studio 2019 extensions for database projects | Machine Learning Model Generation | Important Global Visual Studio 2019 Shortcuts | Datasets for Machine Learning | Top 7 Must-Have Visual Studio 2019 Extensions | AI vs ML vs DL – The basic differences | ASP.NET Core Blazor Server Application Project Structure | ASP.NET Core – Blazor Application an Introduction | Top 5 Machine Learning Frameworks to learn in 2020 ]