In a complex application, it is not enough to create a single object. Often, you need families of objects that work together — without the main logic knowing exactly which classes are used.
This is where Abstract Factory comes in, one of the most elegant creational patterns.
🔍 What is Abstract Factory?
Abstract Factory is a creational design pattern that provides an interface for creating families of interconnected objects, without specifying their concrete classes.
Its purpose is to isolate client code from concrete implementations, allowing the entire "family" of objects to be changed without modifications in the application logic.
🧠 Simple analogy
Imagine you are developing a cross-platform application (.NET MAUI, for example).
You need different buttons and windows for Windows, macOS, and Linux, but the application interface must remain the same.
Instead of writing:
if (platform == "Windows")
button = new WindowsButton();
else if (platform == "Mac")
button = new MacButton();
you can elegantly call:
var guiFactory = new MacFactory();
var button = guiFactory.CreateButton();
var window = guiFactory.CreateWindow();
Thus, you change the entire family of objects (button + window) through a single factory.
⚙️ Implementation in C#
// Abstract Factory
public interface IGUIFactory
{
IButton CreateButton();
IWindow CreateWindow();
}
// Abstract products
public interface IButton { void Render(); }
public interface IWindow { void Open(); }
// Concrete implementations
public class MacFactory : IGUIFactory
{
public IButton CreateButton() => new MacButton();
public IWindow CreateWindow() => new MacWindow();
}
public class WindowsFactory : IGUIFactory
{
public IButton CreateButton() => new WindowsButton();
public IWindow CreateWindow() => new WindowsWindow();
}
// Concrete products
public class MacButton : IButton { public void Render() => Console.WriteLine("Mac Button"); }
public class MacWindow : IWindow { public void Open() => Console.WriteLine("Mac Window"); }
public class WindowsButton : IButton { public void Render() => Console.WriteLine("Windows Button"); }
public class WindowsWindow : IWindow { public void Open() => Console.WriteLine("Windows Window"); }
// Client
class Application
{
private readonly IGUIFactory _factory;
public Application(IGUIFactory factory)
{
_factory = factory;
}
public void Run()
{
var button = _factory.CreateButton();
var window = _factory.CreateWindow();
button.Render();
window.Open();
}
}
🏗️ Advantages
✅ Clearly separates client code from concrete implementations
✅ Allows quick switching of the product family
✅ Promotes consistency among created objects
✅ Simplifies testing and extending the application
⚠️ Disadvantages
❌ Code becomes more complex, with many interfaces
❌ Difficult to extend if you add a new product to all factories
💡 When to use Abstract Factory
-
When the application must work on multiple platforms or UI styles
-
When you want to avoid direct dependencies on concrete classes
-
When you need all created objects to be coherent with each other
🧩 Conclusion
Abstract Factory brings order and consistency to complex architectures.
Through it, you can create coherent ecosystems of objects, without the application logic depending on implementation details — an essential step towards clean, scalable, and testable code in C#.