Abstract Factory Pattern explained simply
Thilan Dissanayaka Software Architecture February 03, 2020

Abstract Factory Pattern explained simply

When you want to create families of related objects without specifying their concrete classes, the Abstract Factory Pattern is your best friend.


What is the Abstract Factory Pattern?

  • Provides an interface for creating families of related or dependent objects.
  • Does not specify their concrete classes.
  • Helps ensure that products from the same family are used together.

In short:

A factory of factories!


Class Diagram

Here is how the pattern maps to a database access layer. The DatabaseFactory is the abstract factory, and each concrete factory (MySQLFactory, PostgreSQLFactory) produces a matching family of products (Connection + QueryBuilder).


Real-Life Analogy

Think about how your application talks to a database. During development you might use MySQL on your local machine, but production runs PostgreSQL. You do not want if (database == "mysql") scattered across every single file that touches the database.

Instead, you build one factory per database family. Each factory knows how to create the right connection and the right query builder for its database. The rest of your code just talks to the factory interface and never knows which database is behind it.

That is the Abstract Factory Pattern in action.


Structure

  • Abstract Factory (DatabaseFactory): Interface that declares methods for creating each product in the family.
  • Concrete Factories (MySQLFactory, PostgreSQLFactory): Implementations that produce concrete products belonging to one family.
  • Abstract Products (Connection, QueryBuilder): Interfaces for each kind of product the factory can create.
  • Concrete Products (MySQLConnection, MySQLQueryBuilder, PostgreSQLConnection, PostgreSQLQueryBuilder): The actual objects. Each concrete factory creates its own variant.

Example in Java

Abstract Product Interfaces

public interface Connection {
    void connect();
    void close();
}

public interface QueryBuilder {
    String select(String table);
    String insert(String table, String[] columns);
}

Concrete Products – MySQL Family

public class MySQLConnection implements Connection {
    @Override
    public void connect() {
        System.out.println("Connected to MySQL database.");
    }

    @Override
    public void close() {
        System.out.println("MySQL connection closed.");
    }
}

public class MySQLQueryBuilder implements QueryBuilder {
    @Override
    public String select(String table) {
        return "SELECT * FROM `" + table + "` LIMIT 100;";
    }

    @Override
    public String insert(String table, String[] columns) {
        return "INSERT INTO `" + table + "` (" + String.join(", ", columns) + ") VALUES (...);";
    }
}

Concrete Products – PostgreSQL Family

public class PostgreSQLConnection implements Connection {
    @Override
    public void connect() {
        System.out.println("Connected to PostgreSQL database.");
    }

    @Override
    public void close() {
        System.out.println("PostgreSQL connection closed.");
    }
}

public class PostgreSQLQueryBuilder implements QueryBuilder {
    @Override
    public String select(String table) {
        return "SELECT * FROM \"" + table + "\" FETCH FIRST 100 ROWS ONLY;";
    }

    @Override
    public String insert(String table, String[] columns) {
        return "INSERT INTO \"" + table + "\" (" + String.join(", ", columns) + ") VALUES (...) RETURNING id;";
    }
}

Notice the small but real differences. MySQL uses backtick-quoted identifiers and LIMIT, while PostgreSQL uses double-quoted identifiers and FETCH FIRST ... ROWS ONLY. Each family encapsulates its own dialect so the calling code never has to care.

Abstract Factory

public interface DatabaseFactory {
    Connection createConnection();
    QueryBuilder createQueryBuilder();
}

Concrete Factories

public class MySQLFactory implements DatabaseFactory {
    @Override
    public Connection createConnection() {
        return new MySQLConnection();
    }

    @Override
    public QueryBuilder createQueryBuilder() {
        return new MySQLQueryBuilder();
    }
}

public class PostgreSQLFactory implements DatabaseFactory {
    @Override
    public Connection createConnection() {
        return new PostgreSQLConnection();
    }

    @Override
    public QueryBuilder createQueryBuilder() {
        return new PostgreSQLQueryBuilder();
    }
}

Using the Abstract Factory

public class Application {
    public static void main(String[] args) {
        // Swap this one line to change the entire database family.
        DatabaseFactory factory = new MySQLFactory();

        Connection conn = factory.createConnection();
        QueryBuilder qb = factory.createQueryBuilder();

        conn.connect();
        System.out.println(qb.select("users"));
        System.out.println(qb.insert("users", new String[]{"name", "email"}));
        conn.close();

        System.out.println("---");

        // Switching to PostgreSQL is a one-line change.
        factory = new PostgreSQLFactory();

        conn = factory.createConnection();
        qb = factory.createQueryBuilder();

        conn.connect();
        System.out.println(qb.select("users"));
        System.out.println(qb.insert("users", new String[]{"name", "email"}));
        conn.close();
    }
}

Output:

Connected to MySQL database.
SELECT * FROM `users` LIMIT 100;
INSERT INTO `users` (name, email) VALUES (...);
MySQL connection closed.
---
Connected to PostgreSQL database.
SELECT * FROM "users" FETCH FIRST 100 ROWS ONLY;
INSERT INTO "users" (name, email) VALUES (...) RETURNING id;
PostgreSQL connection closed.

The entire database family changed, but the client code (Application) did not need a single if statement. That is the whole point.


Why Use the Abstract Factory Pattern?

  • Consistency: A MySQLFactory will never accidentally pair a MySQL connection with a PostgreSQL query builder. Products from the same family always match.
  • Scalability: Need to add SQLite support? Create SQLiteFactory, SQLiteConnection, and SQLiteQueryBuilder. Zero changes to existing code.
  • Decoupling: Your business logic depends on Connection and QueryBuilder interfaces, not on MySQL or PostgreSQL classes. You can swap databases from a config file.

Real-World Use Cases

  • Database abstraction layers – exactly the example above. Libraries like JDBC and Hibernate use this pattern internally.
  • Cross-platform UI toolkits – a WindowsUIFactory creates Windows buttons and dialogs, a MacUIFactory creates Mac variants.
  • Cloud provider SDKs – one factory for AWS services, another for GCP, same interface for your application code.
  • Serialization – a JsonSerializerFactory and an XmlSerializerFactory that each produce a matching set of readers and writers.

Abstract Factory vs Factory Method

Factory Method Abstract Factory Pattern
Creates one product Creates families of products
Single factory method Multiple related create methods
e.g. createConnection() e.g. createConnection() + createQueryBuilder() together
Simpler, focused Bigger, ensures family consistency

Summary

The Abstract Factory Pattern is all about producing families of related objects without coupling your code to their concrete classes. When you see yourself needing to swap an entire group of related objects together – like switching from MySQL to PostgreSQL, or from one cloud provider to another – this is the pattern you reach for.

It keeps your families consistent, your code decoupled, and your architecture ready to scale.

ALSO READ
Blockchain 0x000 – Understanding the Fundamentals
May 21, 2020 Web3 Development

Imagine a world where strangers can exchange money, share data, or execute agreements without ever needing to trust a central authority. No banks, no intermediaries, no single point of failure yet...

Identity and Access Management (IAM)
May 11, 2020 Identity & Access Management

Who are you — and what are you allowed to do? That's the fundamental question every secure system must answer. And it's exactly what Identity and Access Management (IAM) is built to solve.

How I built a web based CPU Simulator
May 07, 2020 Pet Projects

As someone passionate about computer engineering, reverse engineering, and system internals, I've always been fascinated by what happens "under the hood" of a computer. This curiosity led me to...

Writing a Shell Code for Linux
Apr 21, 2020 Exploit Development

Shellcode is a small piece of machine code used as the payload in exploit development. In this post, we write Linux shellcode from scratch — starting with a simple exit, building up to spawning a shell, and explaining every decision along the way.

Exploiting a Stack Buffer Overflow on Windows
Apr 12, 2020 Exploit Development

In a previous tutorial we discusses how we can exploit a buffer overflow vulnerability on a Linux machine. I wen through all theories in depth and explained each step. Now today we are going to jump...

Access Control Models
Apr 08, 2020 Identity & Access Management

Access control is one of the most fundamental concepts in security. Every time you set file permissions, assign user roles, or restrict access to a resource, you're implementing some form of access control. But not all access control is created equal...

Exploiting a  Stack Buffer Overflow  on Linux
Apr 01, 2020 Exploit Development

Have you ever wondered how attackers gain control over remote servers? How do they just run some exploit and compromise a computer? If we dive into the actual context, there is no magic happening....

Basic concepts of Cryptography
Mar 01, 2020 Cryptography

Ever notice that little padlock icon in your browser's address bar? That's cryptography working silently in the background, protecting everything you do online. Whether you're sending an email,...

Common Web Application Attacks
Feb 05, 2020 Application Security

Web applications are one of the most targeted surfaces by attackers. This is primarily because they are accessible over the internet, making them exposed and potentially vulnerable. Since these...

Remote Code Execution (RCE)
Jan 02, 2020 Application Security

Remote Code Execution (RCE) is the holy grail of application security vulnerabilities. It allows an attacker to execute arbitrary code on a remote server — and the consequences are as bad as it sounds. In this post, we'll go deep into RCE across multiple languages, including PHP, Java, Python, and Node.js.