The Abstract Factory Pattern is a creational design pattern that provides an interface for creating families of related objects without specifying their concrete classes.

Unlike the Factory Method Pattern, which creates a single object, the Abstract Factory Pattern creates multiple related objects that are designed to work together.

The client interacts only with the abstract factory and abstract product interfaces, allowing entire product families to be replaced without modifying the client code.

The Abstract Factory Pattern is commonly used when applications need to support multiple environments, themes, database vendors, cloud providers, or platform-specific implementations.

Structure

The Abstract Factory Pattern consists of the following participants.

1. The Abstract Factory declares methods for creating each type of product.
2. Concrete Factories create related product families.
3. The Abstract Products define the common interfaces for each product type.
4. Concrete Products implement the abstract product interfaces.
5. The Client works only with the abstract factory and product interfaces.

Java Implementation

Suppose an application supports multiple database vendors. Depending on the selected database, it should create the appropriate connection and query executor objects.

Both objects belong to the same product family and must work together. Create the abstract products.
public interface DatabaseConnection {
    void connect();
}
public interface QueryExecutor {
    void execute(String query);
}
Create the MySQL products.
public class MySqlConnection implements DatabaseConnection {
    @Override
    public void connect() {
        System.out.println("Connected to MySQL.");
    }
}
public class MySqlQueryExecutor implements QueryExecutor {
    @Override
    public void execute(String query) {
        System.out.println("Executing MySQL query: " + query);
    }
}
Create the PostgreSQL products.
public class PostgreSqlConnection implements DatabaseConnection {
    @Override
    public void connect() {
        System.out.println("Connected to PostgreSQL.");
    }
}
public class PostgreSqlQueryExecutor implements QueryExecutor {
    @Override
    public void execute(String query) {
        System.out.println("Executing PostgreSQL query: " + query);
    }
}
Create the abstract factory.
public interface DatabaseFactory {
    DatabaseConnection createConnection();
    QueryExecutor createQueryExecutor();
}
Create the concrete factories.
public class MySqlFactory implements DatabaseFactory {
    @Override
    public DatabaseConnection createConnection() {
        return new MySqlConnection();
    }
    @Override
    public QueryExecutor createQueryExecutor() {
        return new MySqlQueryExecutor();
    }
}
public class PostgreSqlFactory implements DatabaseFactory {
    @Override
    public DatabaseConnection createConnection() {
        return new PostgreSqlConnection();
    }
    @Override
    public QueryExecutor createQueryExecutor() {
        return new PostgreSqlQueryExecutor();
    }
}
The client works only with the abstract factory.
public class Main {
    public static void main(String[] args) {
        DatabaseFactory factory = new MySqlFactory();

        DatabaseConnection connection = factory.createConnection();
        QueryExecutor executor = factory.createQueryExecutor();

        connection.connect();
        executor.execute("SELECT * FROM employees");
    }
}
Output:
Connected to MySQL.
Executing MySQL query: SELECT * FROM employees

How It Works?

The client first selects the appropriate DatabaseFactory implementation based on the desired database vendor.

The concrete factory creates all related objects that belong to the same product family. In this example, both the connection and query executor are MySQL implementations.

The client interacts only with the abstract interfaces and remains unaware of the concrete classes being instantiated.

If the application needs to switch to PostgreSQL, only the factory implementation changes. The client code continues to use the same interfaces without modification.

Advantages

1. It creates families of related objects that are designed to work together.
2. It hides concrete implementation classes from the client.
3. Entire product families can be replaced without changing client code.
4. It promotes consistency by ensuring compatible objects are created together.

Disadvantages

1. Introducing new product types requires changes to every factory implementation.
2. The pattern introduces additional interfaces and classes, increasing complexity.
3. It may be unnecessary for applications that create only a single type of object.

JDK Examples

The Abstract Factory Pattern appears throughout the Java ecosystem.

1. The javax.xml.parsers.DocumentBuilderFactory creates related XML processing objects such as DocumentBuilder.

2. The javax.xml.transform.TransformerFactory creates compatible transformer-related objects while hiding the underlying implementation.

Summary

The Abstract Factory Pattern creates families of related objects without exposing their concrete implementations to the client.

By separating object creation from object usage, the pattern provides flexibility, consistency, and portability, making it ideal for applications that support multiple implementations of the same product family.
Nagesh Chauhan

Nagesh Chauhan

Principal Software Engineer • Java • Python • Distributed Systems • AI/ML

Principal Software Engineer with 14+ years of experience designing and delivering large-scale distributed systems, cloud-native applications, and AI-powered platforms.

Passionate about solving complex engineering problems using strong data structures and algorithms, along with expertise in Java, Spring Boot, Python, System Design, Microservices, Cloud, Kafka, Elasticsearch, and Generative AI.

Share this Article

💬 Comments

Join the Discussion