Factory Design Pattern in C# with Codes

What is Factory Design Pattern in C#?

Factory design pattern implements the concept of real world factories. Factory pattern is a creational design pattern. It deals with creating objects without specifying exact class. In general, actors of factory patterns are a client, a factory and a product. Client is an object that requires another object for some purposes. Rather than creating the product instance directly, the client delegates this responsibility to the factory. The factory then creates a new instance of the product, passing it back to the client. 

What are benefits of Factory Design Patterns

Using a Factory design pattern has the following benefits:

  • Product implementation may change over time but the client remains unchanged.
  • Factory encapsulates the logic of creating an object that can be reused by many clients.

Sample application without factory pattern 

I’m going to use a sample bank card application which is used by many other blogs. However, it is the most easy way to explain the concept. We can use another sample like vehicle(car/bike/bicycle) but I stick with the bank card sample for now. 

We are going to use .NET 6.0 with Visual Studio 2022 as usual. The source code can be access here https://github.com/binhn8/FactoryPatternSample/tree/features/not-using-factory-pattern 

Create a CreditCard interface and three classes for three type of card: Gold, Silver Standard as bellow

public interface CreditCard
    {
        CardType GetCardType();
        int GetCreditLimit();
        int GetAnnualCharge();
    }

class CreditCardGold:CreditCard
	{
		public CardType GetCardType()
		{
			return CardType.Gold;
		}
		public int GetCreditLimit()
		{
			return 10000;
		}
		public int GetAnnualCharge()
		{
			return 200;
		}
	}

class CreditCardSilver:CreditCard
	{
		public CardType GetCardType()
		{
			return CardType.Silver;
		}
		public int GetCreditLimit()
		{
			return 5000;
		}
		public int GetAnnualCharge()
		{
			return 100;
		}
	}

class CreditCardStandard : CreditCard
	{
		public CardType GetCardType()
		{
			return CardType.Standard;
		}
		public int GetCreditLimit()
		{
			return 3000;
		}
		public int GetAnnualCharge()
		{
			return 50;
		}
	}

For the main program, add a these line of codes

using FactoryPatternSample;

CardType cardType = CardType.Gold;
CreditCard cardDetails = null;

if (cardType == CardType.Standard)
{
    cardDetails = new CreditCardStandard();
}
else if (cardType == CardType.Silver)
{
    cardDetails = new CreditCardSilver();
}
else if (cardType == CardType.Gold)
{
    cardDetails = new CreditCardGold();
}
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();

So we will the program run correctly and display the correct information of card

What is the problem with the above code implementation?

So we will run the program correctly and display the correct information on the card but what are the problems with the above code samples.

There are obvious issue with the above approach:

  1. There is tight coupling between the client class (the program) and the CreditCardStandard, CreditCardSilver, CreditCardGold classes.  
  2. If we would like to add a new CreditCard type such as Platinum we will need to change the client class which is not really ideal.

Let’s see how we fix the above issues with factory patterns.

Sample application with factory pattern

Factory Design Patterns help with creating objects without exposing the logic of creating to the client. The client will refer to the new object via an interface. So the client won’t care about the creating object, it is factory responsibility. Client just asks and then the factory will produce the correct object to the client.

The source code for refactor branch can be access in here https://github.com/binhn8/FactoryPatternSample/tree/features/using-factory-pattern 

Create a factory class named CreditCardFactory.cs and add following codes

public class CreditCardFactory
	{
		public static CreditCard GetCreditCardDetails(CardType cardType)
		{
			CreditCard cardDetails = null;

			if (cardType == CardType.Standard)
			{
				cardDetails = new CreditCardStandard();
			}
			else if (cardType == CardType.Silver)
			{
				cardDetails = new CreditCardSilver();
			}
			else if (cardType == CardType.Gold)
			{
				cardDetails = new CreditCardGold();
			}
			return cardDetails;
		}
	}

Basilly, we can see we moved the logic from the client to the factory class.

Now change the client class with following code

The client just ask the factory for the object by using this method CreditCardFactory.GetCreditCardDetails(cardType); and factory will return the correct object based on the input parameter

Rerun the application and the code is the same

Conclusion and next step

The above sample is the simplest explanation with source code for Factory Pattern. I hope you can understand the concept easily. Still there are couple of issues with the above codes after refactoring: 

  • When adding a new credit card type, we still need to modify CreditCardFactory.cs. By doing it, we violate the open-close principle of SOLID principal (“Open for extension but close for modification”)
  • We have tight coupling between CreditCardFactory.cs and CreditCardStandard, CreditCardSilver, CreditCardGold classes. 

We will sort out this issue in the next refactor step in the next article later.  Factory Pattern is one of the most popular patterns and I hope you enjoy the basic concept.

Here are source code which I develop and use in the sample:

To run the sample code, you will need to use NET 6.0. I’m using Visual Studio 2022. I hope you enjoy it!

Happy coding!

Ben Binh Q Nguyen


Posted

in

by

Tags:

Comments

One response to “Factory Design Pattern in C# with Codes”

  1. Vinh Avatar
    Vinh

    Thanks for your sharing. It is beneficial.

Leave a Reply

Your email address will not be published. Required fields are marked *