Introduction
In software design, Factory Patterns play a pivotal role in object creation, providing a flexible and maintainable way to instantiate objects. Two prominent members of the Factory Pattern family are the Factory Pattern and the Abstract Factory Pattern.
In this blog, we'll delve into the nuances of each pattern, providing code snippets in C# and real-world examples to illustrate their applications.
1. Factory Pattern
The Factory Pattern is a creational design pattern that provides an interface for creating instances of a class, but leaves the choice of its type to the subclasses, creation being deferred at runtime.
public interface IProduct
{
void DisplayInfo();
}
public class ConcreteProductA : IProduct
{
public void DisplayInfo()
{
Console.WriteLine("Product A");
}
}
public class ConcreteProductB : IProduct
{
public void DisplayInfo()
{
Console.WriteLine("Product B");
}
}
public class SimpleFactory
{
public IProduct CreateProduct(string type)
{
return type switch
{
"A" => new ConcreteProductA(),
"B" => new ConcreteProductB(),
_ => throw new ArgumentException("Invalid product type"),
};
}
}
// Usage
var factory = new SimpleFactory();
var productA = factory.CreateProduct("A");
productA.DisplayInfo();
Real-World Example
Consider a document processing application where the Factory Pattern is used to create different types of documents, such as PDFs and Word documents.
2. Abstract Factory Pattern
The Abstract Factory Pattern is an extension of the Factory Pattern, where an interface is responsible for creating a family of related or dependent objects without specifying their concrete classes.
public interface IAbstractFactory
{
IProductA CreateProductA();
IProductB CreateProductB();
}
public interface IProductA
{
void DisplayInfo();
}
public interface IProductB
{
void DisplayInfo();
}
public class ConcreteFactory1 : IAbstractFactory
{
public IProductA CreateProductA()
{
return new ConcreteProductA1();
}
public IProductB CreateProductB()
{
return new ConcreteProductB1();
}
}
public class ConcreteFactory2 : IAbstractFactory
{
public IProductA CreateProductA()
{
return new ConcreteProductA2();
}
public IProductB CreateProductB()
{
return new ConcreteProductB2();
}
}
public class ConcreteProductA1 : IProductA
{
public void DisplayInfo()
{
Console.WriteLine("Product A1");
}
}
public class ConcreteProductB1 : IProductB
{
public void DisplayInfo()
{
Console.WriteLine("Product B1");
}
}
public class ConcreteProductA2 : IProductA
{
public void DisplayInfo()
{
Console.WriteLine("Product A2");
}
}
public class ConcreteProductB2 : IProductB
{
public void DisplayInfo()
{
Console.WriteLine("Product B2");
}
}
// Usage
var factory1 = new ConcreteFactory1();
var productA1 = factory1.CreateProductA();
productA1.DisplayInfo();
Real-World Example
Consider a user interface toolkit where the Abstract Factory Pattern is used to create different UI components (buttons, text boxes) for different operating systems (Windows, macOS).
Factory Pattern vs Abstract Factory Pattern
1. Intent
- Factory Pattern: Creates a single type of object.
- Abstract Factory Pattern: Creates families of related or dependent objects.
2. Complexity
- Factory Pattern: Simpler, deals with the creation of one type of object.
- Abstract Factory Pattern: More complex, deals with multiple related objects.
3. Number of Classes
- Factory Pattern: Involves fewer classes.
- Abstract Factory Pattern: Involves more classes, especially when dealing with families of objects.
4. Real-World Analogy
- Factory Pattern: A bakery producing different types of cakes.
- Abstract Factory Pattern: A bakery producing cakes, cookies, and pastries – a family of related bakery products.
5. Code Snippet
- Factory Pattern: Uses a single factory method to create one type of object.
- Abstract Factory Pattern: Uses multiple factory methods to create families of related objects.
Conclusion
Both the Factory Pattern and the Abstract Factory Pattern serve essential roles in object creation, but their application contexts differ. Choose the Factory Pattern for simpler scenarios where the creation of a single type of object suffices. Opt for the Abstract Factory Pattern when dealing with families of related objects or when a system needs to be independent of how its objects are created, composed, and represented.
As you navigate the realm of design patterns in .NET development, understanding when to apply each pattern will empower you to craft maintainable and scalable solutions.
Happy coding!