Factory Method pattern in C#
Hi there! Welcome to my blog where I share my passion for C# and design patterns. Today I’m going to talk about one of the most popular and useful design patterns: the Factory Method pattern.š
What is the Factory Method pattern?
The Factory Method pattern is a creational design pattern that defines an interface for creating an object but lets subclasses decide which class to instantiate. This pattern lets a class defer instantiation to subclasses.
In other words, the Factory Method pattern allows us to create objects without exposing the creation logic to the client. Instead of using a constructor or a simple factory, we use an abstract method (or an interface) that returns an object of a specific type. The subclasses can then override this method and return different types of objects based on some criteria.
Why use the Factory Method pattern?
The Factory Method pattern is useful when we want to:
- Decouple the creation of objects from their usage
- Encapsulate the object creation logic and make it more flexible and extensible
- Avoid hard-coding the class names in the client code
- Support multiple types of objects with a common interface
- Handle complex dependencies between objects
How to implement the Factory Method pattern in C#?
Let’s see how we can implement the Factory Method pattern in C# with a currency-related example. Suppose we have an interface called ICurrency that defines some common properties and methods for different currencies:
// The 'Product' interface
public interface ICurrency
{
string Name { get; }
string Symbol { get; }
decimal ExchangeRate { get; }
void DisplayInfo();
}
We can then create some concrete classes that implement this interface, such as USDCurrency, CADCurrency, and GBPCurrency:
// A 'ConcreteProduct' class
public class USDCurrency : ICurrency
{
public string Name => "United States Dollar";
public string Symbol => "$";
public decimal ExchangeRate => 1.25m; // 1 USD = 1.25 CAD
public void DisplayInfo()
{
Console.WriteLine($"The currency of USA is {Name} ({Symbol})");
Console.WriteLine($"The exchange rate is {ExchangeRate} CAD per USD");
}
}
// Another 'ConcreteProduct' class
public class CADCurrency : ICurrency
{
public string Name => "Canadian Dollar";
public string Symbol => "C$";
public decimal ExchangeRate => 0.8m; // 1 CAD = 0.8 USD
public void DisplayInfo()
{
Console.WriteLine($"The currency of Canada is {Name} ({Symbol})");
Console.WriteLine($"The exchange rate is {ExchangeRate} USD per CAD");
}
}
// Yet another 'ConcreteProduct' class
public class GBPCurrency : ICurrency
{
public string Name => "British Pound Sterling";
public string Symbol => "£";
public decimal ExchangeRate => 1.7m; // 1 GBP = 1.7 CAD
public void DisplayInfo()
{
Console.WriteLine($"The currency of UK is {Name} ({Symbol})");
Console.WriteLine($"The exchange rate is {ExchangeRate} CAD per GBP");
}
}
Now, instead of creating these objects directly in the client code, we can use an abstract class (or an interface) called CurrencyFactory that defines a factory method for creating ICurrency objects:
// The 'Creator' abstract class
public abstract class CurrencyFactory
{
// The factory method that returns an ICurrency object
public abstract ICurrency CreateCurrency();
}
We can then create some concrete subclasses that override this method and return different types of ICurrency objects based on some criteria, such as the country name:
// A 'ConcreteCreator' class
public class USACurrencyFactory : CurrencyFactory
{
// Override the factory method to return a USDCurrency object
public override ICurrency CreateCurrency()
{
return new USDCurrency();
}
}
// Another 'ConcreteCreator' class
public class CanadaCurrencyFactory : CurrencyFactory
{
// Override the factory method to return a CADCurrency object
public override ICurrency CreateCurrency()
{
return new CADCurrency();
}
}
// Yet another 'ConcreteCreator' class
public class UKCurrencyFactory : CurrencyFactory
{
// Override the factory method to return a GBPCurrency object
public override ICurrency CreateCurrency()
{
return new GBPCurrency();
}
}
Finally, in the client code, we can use the CurrencyFactory class to create and use ICurrency objects without knowing their concrete types:
// The 'Client' class
class Program
{
static void Main(string[] args)
{
// Create a CurrencyFactory object based on the country name
CurrencyFactory factory = GetCurrencyFactory("USA");
// Use the factory method to create an ICurrency object
ICurrency currency = factory.CreateCurrency();
// Use the ICurrency object
currency.DisplayInfo();
// Output:
// The currency of USA is United States Dollar ($)
// The exchange rate is 1.25 CAD per USD
}
// A helper method that returns a CurrencyFactory object based on the country name
static CurrencyFactory GetCurrencyFactory(string country)
{
switch (country)
{
case "USA":
return new USACurrencyFactory();
case "Canada":
return new CanadaCurrencyFactory();
case "UK":
return new UKCurrencyFactory();
default:
throw new ArgumentException("Invalid country");
}
}
}
As you can see, the Factory Method pattern allows us to create and use different types of ICurrency objects without exposing the creation logic to the client. We can also easily add more types of currencies by creating new subclasses of CurrencyFactory and ICurrency.š
Conclusion
The Factory Method pattern is a powerful design pattern that helps us create objects without exposing the creation logic to the client. It also makes our code more flexible and extensible by decoupling the object creation from their usage.š
If you want to learn more about the Factory Method pattern and other design patterns in C#, I recommend you check out these resources:
- Factory Method Design Pattern in C# - Dot Net Tutorials1
- C# Factory Method Design Pattern - Dofactory2
- How to Turn C# Factory Method Pattern Into Creation Force3
I hope you enjoyed this article and learned something new. Please leave a comment below and share your thoughts and feedback. Also, don’t forget to subscribe to my blog for more awesome articles on C# and design patterns.
You can find the code examples here: source code
See you next time!š
Comments
Post a Comment