DEV Community

Spyros Ponaris
Spyros Ponaris

Posted on

Abstract Factory Pattern in C# – Step-by-Step Tutorial

Abstract Factory Pattern in C# – Step-by-Step Tutorial (Using My Project)

In this tutorial, I’ll explain how I implemented the Abstract Factory Pattern in C# using my project:

GitHub Repository: https://github.com/stevsharp/AbstractFactoryDemo

This project demonstrates how to support multiple database providers like:

  • SQL Server
  • MySQL

Each database needs related objects such as:

  • Database Connection
  • Database Command

Instead of hardcoding these objects directly, we use the Abstract Factory Pattern to make the code cleaner and scalable.


Step 1: The Problem

Imagine your application supports multiple databases.

Without using Abstract Factory, your code may look like this:

if(databaseType == "SQL")
{
    var connection = new SqlConnection();
    var command = new SqlCommand();
}
else
{
    var connection = new MySqlConnection();
    var command = new MySqlCommand();
}
Enter fullscreen mode Exit fullscreen mode

Why this is bad:

  • Too many if/else statements
  • Hard to maintain
  • Difficult to scale
  • Tight coupling with concrete classes

We need a better approach.


Step 2: Create Abstract Products

These interfaces define common behavior for all database implementations.

IDbConnection.cs

public interface IDbConnection
{
    void Connect();
}
Enter fullscreen mode Exit fullscreen mode

IDbCommand.cs

public interface IDbCommand
{
    void Execute();
}
Enter fullscreen mode Exit fullscreen mode

Now every database provider must implement these interfaces.


Step 3: Create SQL Server Products

SqlConnection.cs

public class SqlConnection : IDbConnection
{
    public void Connect()
    {
        Console.WriteLine("Connecting to SQL Server...");
    }
}
Enter fullscreen mode Exit fullscreen mode

SqlCommand.cs

public class SqlCommand : IDbCommand
{
    public void Execute()
    {
        Console.WriteLine("Executing SQL command...");
    }
}
Enter fullscreen mode Exit fullscreen mode

These classes handle SQL Server operations.


Step 4: Create MySQL Products

MySqlConnection.cs

public class MySqlConnection : IDbConnection
{
    public void Connect()
    {
        Console.WriteLine("Connecting to MySQL...");
    }
}
Enter fullscreen mode Exit fullscreen mode

MySqlCommand.cs

public class MySqlCommand : IDbCommand
{
    public void Execute()
    {
        Console.WriteLine("Executing MySQL command...");
    }
}
Enter fullscreen mode Exit fullscreen mode

These classes handle MySQL operations.


Step 5: Create the Abstract Factory

Now we create a factory interface.

IDatabaseFactory.cs

public interface IDatabaseFactory
{
    IDbConnection CreateConnection();
    IDbCommand CreateCommand();
}
Enter fullscreen mode Exit fullscreen mode

This ensures every factory creates:

  • Connection objects
  • Command objects

Step 6: Create SQL Server Factory

SqlServerFactory.cs

public class SqlServerFactory : IDatabaseFactory
{
    public IDbConnection CreateConnection()
    {
        return new SqlConnection();
    }

    public IDbCommand CreateCommand()
    {
        return new SqlCommand();
    }
}
Enter fullscreen mode Exit fullscreen mode

This factory creates SQL-related objects.


Step 7: Create MySQL Factory

MySqlFactory.cs

public class MySqlFactory : IDatabaseFactory
{
    public IDbConnection CreateConnection()
    {
        return new MySqlConnection();
    }

    public IDbCommand CreateCommand()
    {
        return new MySqlCommand();
    }
}
Enter fullscreen mode Exit fullscreen mode

This factory creates MySQL-related objects.


Step 8: Use the Factory in Client Code

Now the client works with the factory instead of concrete classes.

Program.cs

class Program
{
    static void Main()
    {
        IDatabaseFactory factory = new MySqlFactory();

        var connection = factory.CreateConnection();
        var command = factory.CreateCommand();

        connection.Connect();
        command.Execute();
    }
}
Enter fullscreen mode Exit fullscreen mode

Output

Connecting to MySQL...
Executing MySQL command...
Enter fullscreen mode Exit fullscreen mode

Step 9: Why This Pattern Is Useful

Let’s say your application needs to support PostgreSQL in the future.

You would simply add:

  • PostgresConnection
  • PostgresCommand
  • PostgresFactory

And your client code stays exactly the same.

That makes your code:

✅ Flexible
✅ Maintainable
✅ Scalable
✅ Easy to test


Visual Flow

Client
   ↓
IDatabaseFactory
   ↓
--------------------------------
↓                              ↓
SqlServerFactory         MySqlFactory
↓                              ↓
SqlConnection            MySqlConnection
SqlCommand               MySqlCommand
Enter fullscreen mode Exit fullscreen mode

Real Interview Explanation

Here’s how you can explain this in an interview:

In this project, I used the Abstract Factory Pattern to create families of related database objects. Each database provider creates its own connection and command objects. This reduces tight coupling and makes the application easier to extend when adding new databases.


When Should You Use Abstract Factory?

Use Abstract Factory when:

  • You need to create families of related objects
  • You want loose coupling
  • Your system supports multiple implementations
  • You want easier scalability

Examples:

  • Database providers
  • UI themes
  • Payment gateways
  • Cloud providers

Final Thoughts

Abstract Factory is a great design pattern when your application needs flexibility.

Instead of hardcoding object creation logic everywhere, you centralize it through factories and keep your code clean.

If you want to see the full implementation, check out the repository:

https://github.com/stevsharp/AbstractFactoryDemo


Reference

https://refactoring.guru/design-patterns/abstract-factory


This version is fully formatted for Dev.to Markdown, so you can paste it directly into your article editor.

Top comments (0)