Back to: Design Patterns in C# With Real-Time Examples
Factory Design Pattern in C# with Real-Time Example
In this article, I am going to discuss the Factory Design Pattern in C# with examples. The Factory Design Pattern is one of the most frequently used design patterns in real-time applications. The Factory Design Pattern in C# falls under the Creational Design Patterns Category. As part of this article, we are going to discuss the following pointers related to the Factory Design Pattern.
- What is Factory Design Pattern?
- Understanding the Factory Design Pattern.
- Example without using the Factory Pattern in C#.
- Understanding the Problem of not using the Factory Design Pattern
- Implementing the Factory Design Pattern in C#?
- When to use Factory Design Pattern in Real-time Application?
- Problems of the Simple Factory Design Pattern.
What is Factory Design Pattern in C#?
Let us first try to understand the definitions of the factory design pattern. If you are not understanding the following definition, then don’t worry, we will explain the same with real-time examples and then definitely you will understand the definition.
According to Gang of Four (GoF), the Factory Design Pattern states that A factory is an object which is used for creating other objects. In technical terms, we can say that a factory is a class with a method. That method will create and return different types of objects based on the input parameter, it received.
In simple words, if we have a superclass and n number of subclasses, and based on the data provided, if we have to create and return the object of one of the subclasses, then we need to use the Factory Design Pattern in C#.
In the Factory Design pattern, we create an object without exposing the Object Creation and Initialization logic to the client and the client will refer to the newly created object using a common interface. The basic principle behind the Factory Design Pattern is that, at run time, we get an object of a similar type based on the parameter we pass. So, the client will get the appropriate object and consume the object without knowing how the object is created and initialized.
Real-Time Example to Understand Factory Design Pattern in C#
Let us understand the Factory Design Pattern with one Real-Time Example. We are going to develop an application for showing Credit Card Details.
Please have a look at the following diagram. Here, as you can see we have three credit card classes i.e. MoneyBack, Titanium, and Platinum and these three classes are the subclasses of the CreditCard superclass or, you can say, super interface. The CreditCard superclass or super interface has three methods i.e. GetCardType, GetCreditLimit, and GetAnnualCharge. The subclasses i.e. MoneyBack, Titanium, and Platinum have implemented the above three methods of the CreditCard.
Our requirement is, we will ask the user to select the credit card. Once the user selects the credit card then we need to display the required information about that selected credit card. Let us first discuss how to achieve this without using the Factory Design Pattern in C#. Then we will discuss the problems and finally, we will create the same application using the Factory Design Pattern in C#.
Example Without using Factory Design Pattern in C#
Let us first see the example without using the Factory Design Pattern. It’s very simple and straight forwards, Let us proceed and implement this step by step.
Step 1: Create the Abstract Product or Product Interface (CreditCard)
Here we need to create either an interface or an abstract class that will expose the operations a credit card should have. So, create a class file with the name CreditCard.cs and then copy and paste the following code into it. As you can see, we created the CreditCard interface with three methods as per our requirements.
namespace FactoryDesignPattern { public interface CreditCard { string GetCardType(); int GetCreditLimit(); int GetAnnualCharge(); } }
Now we need to create three Product classes that will implement the above interface.
Step 2: Creating Product Classes (MoneyBack, Titanium, and Platinum)
In our example, we have three Credit cards. So, we need to create three classes by implementing the CreditCard Interface and providing implementation to all three CreditCard methods. First, create a class file with the name MoneyBack.cs and then copy and paste the following code into it.
namespace FactoryDesignPattern { class MoneyBack : CreditCard { public string GetCardType() { return "MoneyBack"; } public int GetCreditLimit() { return 15000; } public int GetAnnualCharge() { return 500; } } }
As you can see this class implements the CreditCard interface and provide implementation to all three methods. Similarly, we need to do the same thing for the other two credit card classes.
Titanium.cs:
Create a class file with the name Titanium.cs and then copy and paste the following code into it.
namespace FactoryDesignPattern { public class Titanium : CreditCard { public string GetCardType() { return "Titanium Edge"; } public int GetCreditLimit() { return 25000; } public int GetAnnualCharge() { return 1500; } } }
Platinum.cs:
Create a class file with the name Platinum.cs and then copy and paste the following code into it.
namespace FactoryDesignPattern { public class Platinum : CreditCard { public string GetCardType() { return "Platinum Plus"; } public int GetCreditLimit() { return 35000; } public int GetAnnualCharge() { return 2000; } } }
So, we have created three Product classes that implement the CreditCard interface. Next, we need to consume the Product classes inside the client code by creating and initializing the appropriate Product class object.
Step 3: Client Code (Main Method)
Client Code is nothing but the class from where we need to consume the product classes (MoneyBack, Titanium, and Platinum). And in our example, it is going to be the Main method of the Program class. Now in the client code, we will ask the user to select the Credit Card Type. And based on the Selected Credit card, we will create an instance of any one of the above three product implementation classes (MoneyBack, Titanium, and Platinum) and call the methods to show the credit card details. So, modify the Main method of the Program class as follows. The following example code is self-explained, so please go through the comment lines for a better understanding.
using System; namespace FactoryDesignPattern { class Program { static void Main(string[] args) { //Generally we will get the Card Type from UI. //Here we are hardcoded the card type string cardType = "MoneyBack"; CreditCard cardDetails = null; //Based of the CreditCard Type we are creating the //appropriate type instance using if else condition if (cardType == "MoneyBack") { cardDetails = new MoneyBack(); } else if (cardType == "Titanium") { cardDetails = new Titanium(); } else if (cardType == "Platinum") { cardDetails = new Platinum(); } if (cardDetails != null) { Console.WriteLine("CardType : " + cardDetails.GetCardType()); Console.WriteLine("CreditLimit : " + cardDetails.GetCreditLimit()); Console.WriteLine("AnnualCharge :" + cardDetails.GetAnnualCharge()); } else { Console.Write("Invalid Card Type"); } Console.ReadLine(); } } }
The above code implementation is very straightforward. Once we get the CardType value, then by using the IF-ELSE Condition we are creating the appropriate Credit Card instance. Then we are just calling the three methods to display the credit card information on the console window. So, when you run the application, you will get the output as expected as shown below.
What is the Problem with the above Code Implementation?
The above code implementation introduces the following problems
- First, the Tight Coupling between the client class (Program) and Product Classes (MoneyBack, Titanium, and Platinum). So, when we do changes in one class, then we also need to do changes in the other classes.
- Secondly, if we add a new Credit Card, then also we need to modify the client code i.e. The main method of the Program class by adding an extra IF-ELSE Condition which not only overheads in the development but also in the testing process
Let us see how to overcome the above problem by using the Factory Design Pattern in C#.
Factory Design Pattern Implementation in C#:
As per the definition of Factory Design Pattern, the Factory Design Pattern create an object without exposing the object creation logic to the client and the client refers to the newly created object using a common interface.
Please have a look at the following image. This is our factory class and this class takes the responsibility of creating and returning the appropriate Product (i.e. MoneyBack, Titanium, and Platinum) object. As you can see, this class has one static method i.e. GetCreditcard and this method takes one input parameter and based on the parameter value it will create one of the credit card (i.e. MoneyBack, Platinum, and Titanium) objects and store that object in the superclass (CrditCard) reference variable and finally return that superclass reference variable to the caller of this method i.e. to the client or you can say in our example it is the Main method of the Program class.
Now the client needs to get the object through CreditCardFactory. For example, if the client wants to create an instance of Platinum Credit then he/she needs to do something like the below. As you can see, he/she needs to pass the Credit card type to the GetCreditcard method of the CreditCardFactory class. Now, the GetCreditcard() method will create a Platinum class instance and return that instance to the client.
Step 4: Creating Factory Class
Create a class file with the name CreditCardfactory.cs and then copy and paste the following into it. This class contains the logic to create and initialize the appropriate object and returns that object based on some condition. As you can see this class contains one static method and that static method takes one string parameter and based on the parameter value, it will create and return the appropriate product instance (MoneyBack, Titanium, and Platinum) to the client.
namespace FactoryDesignPattern { public class CreditCardFactory { public static CreditCard GetCreditCard(string cardType) { CreditCard cardDetails = null; if (cardType == "MoneyBack") { cardDetails = new MoneyBack(); } else if (cardType == "Titanium") { cardDetails = new Titanium(); } else if (cardType == "Platinum") { cardDetails = new Platinum(); } return cardDetails; } } }
Step 5: Using Factory Class in Client Code to Get the Product Instance
Now, we need to modify the client code. So, modify the Main method of the Program class as follows. As you can see, now we are not creating the Product instance using IF-ELSE Condition, rather we are calling the Static GetCreditCard method of the CreditCardFactory class by passing the Credit Card Type which instance we need to create. Once the GetCreditCard method returns the appropriate product instance, then we are consuming the methods as it is. Here, we are storing the object in the super interface GetCreditCard.
using System; namespace FactoryDesignPattern { class Program { static void Main(string[] args) { CreditCard cardDetails = CreditCardFactory.GetCreditCard("Platinum"); if (cardDetails != null) { Console.WriteLine("CardType : " + cardDetails.GetCardType()); Console.WriteLine("CreditLimit : " + cardDetails.GetCreditLimit()); Console.WriteLine("AnnualCharge :" + cardDetails.GetAnnualCharge()); } else { Console.Write("Invalid Card Type"); } Console.ReadLine(); } } }
Output:
Factory Design Pattern UML (Class) Diagram:
So, once we understand how to implement the Factory Design Pattern in C#, let us try to understand the UML (Unified Modeling Language) or Class diagram of the Factory Design Pattern. The Unified Modeling Language is a general-purpose, developmental modeling language in the field of software engineering that is intended to provide a standard way to visualize the design of a system. For a better understanding, please have a look at the following diagram which shows the different components of the Factory Design Pattern. Here, I am comparing the Factory Design Pattern UML diagram with our CreditCard example, so that you can easily understand the concept.
Real-Life Example of Factory Pattern:
From Lehman’s point of view, we can say that a factory is a place where products are created. In order words, we can say that it is a centralized place for creating products. Later, based on the order received, the appropriate product is delivered by the factory. For example, a car factory can produce different types of cars. If you are ordering a car, then based on your requirements or specifications, the factory will create the appropriate car and then deliver that car to you.
The same thing also happens in the Factory Design Pattern. A factory (i.e. a class) will create and deliver products (i.e. objects) based on the incoming parameters.
When to use the Factory Design Pattern in Real-Time Applications?
It would not be a good programming approach to specify the exact class name while creating the objects by the client which leads to tight coupling between the client and the product. To overcome this problem, we need to use the Factory Design Pattern in C#. This design pattern provides the client with a simple mechanism to create the object. So, we need to use the Factory Design Pattern in C# when
- The Object needs to be extended to the subclasses
- Classes don’t know what exact sub-classes it has to create
- The Product implementation going to change over time and the Client remains unchanged
Problems of Simple Factory Pattern in C#
- If we need to add any new product (i.e. new credit card) then we need to add a new if else condition in the GetCreditCard method of the CreditCardFactory class. This violates the open/closed design principle.
- We also have a tight coupling between the Factory (CreditCardFactory) class and Product classes (MoneyBack, Titanium, and Platinum).
In the next article, I am going to discuss how to overcome the above problem by using the Factory Method Design Pattern in C#. Here, in this article, I try to explain the Factory Design Pattern in C# with Examples. I hope this article will help you with your needs. I would like to have your feedback. Please post your feedback, question, or comments about this article.
I have one doubt ..
If one new client want one more method like GetAccountDetails()
What will be the approach??
any way awesome article..really helped a lot to understand..
It’s very logical question
Interface segregation
not related at all.
ISP: https://dotnettutorials.net/lesson/interface-segregation-principle/
its about make interface thicker, not wider.
Suman,adding GetAccountDetails() should be added to the interface Credit Card classed will be compelled to implement it,
Good and Simple to understand.
BEST
Good work. 🙂
Awesome Article
Excellent transmission of knowledge regarding design patterns in c #.
Awesome article really its helping a lot to understand the actual concept.
Simply Awesome!!
Very nice e.g.
Thank you for this course.
you have managed to make the course very easy for everyone
I really want to read the next lesson
Excellent article in a very great detail ,really helped me to understand in
Best article encountered on the topic.
Simple and meaningful explanation.
really thanks for the good examples. usually, I see everyone try to tell you these design patterns but with not real world examples. so it takes more time to learn.
cool
thanks
Very nicely documented article
very simple and real usecase the way of putting the things is wonderful.
Very clear explanation and detailed information, thank you for shering. 🙂
Best I have ever read!
Thanks it helped to understand
Very nicely explained.
Thank you , very well written and was so easy to understand ,was trying to understand design patterns for long but couldn’t understand it properly from the videos and articles I had gone through so far .
Nice