Factory Pattern

📢 This article was translated by gemini-3-flash-preview

Simple Factory Pattern

Simple Factory is a creational pattern, but it is not one of the 23 standard GoF design patterns.

Definition: Define a factory class that returns instances of different classes based on provided arguments. The created instances usually share a common parent class.

Since the methods used to create instances in this pattern are typically static, it is also known as the Static Factory Method pattern.

You pass a parameter for the product you need, and the factory returns the object without you needing to know the implementation details.

Example: A dumpling shop. When a customer wants a specific type of dumpling, the shop produces it. Here, the shop is the Factory, the dumpling is the Product, and the dumpling name is the parameter.

If a customer wants “Leek Dumplings,” “Leek” is the parameter, and the shop returns the specific product (assuming they have it).

Simple Factory Pattern

Three Roles:

  1. Factory (Core) Handles the internal logic for creating all products. It is called directly by the client to create objects.

  2. Abstract Product The parent class for all objects created by the factory, defining common methods. Concrete products inherit from this.

  3. Concrete Product The target of the creation; instances of specific classes created by the factory.

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class SimpleFactory{
    public static void main(String[] args){
        Product productA = Factory.createProduct("A");
        productA.info();
        // ...
    }
}

abstract class Product{
    public abstract void info();
}

class ProductA extends Product{
    @Override
    public void info(){
        System.out.println("A");
    }
}

class ProductB extends Product{
    @Override
    public void info(){
        System.out.println("B");
    }
}

class Factory{
    public static Product createProduct(String type){
        Product p = null;
        // Exception handling omitted for brevity
        switch(type){
            case "A":
                p = new ProductA();
                break;
            case "B":
                p = new ProductB();
                break;
            default:
                System.out.println("Please try again");
                break;
        }
        
        return p;
    }
}

Adding a new product requires modifying the factory class, which violates the Open-Closed Principle.

Factory Method Pattern

Factory Method Pattern - A Class Creational Pattern.

Intent

Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

Structure

Factory Method Pattern

Roles:

  • Product: Defines the interface for the objects the factory method creates.
  • ConcreteProduct: Implements the Product interface.
  • Creator: Declares the factory method, which returns an object of type Product. It may also define a default implementation that returns a default ConcreteProduct.
  • ConcreteCreator: Overrides the factory method to return an instance of a ConcreteProduct.

Applicability

Use the Factory Method pattern when:

  • A class can’t anticipate the class of objects it must create.
  • A class wants its subclasses to specify the objects it creates.
  • Classes delegate responsibility to one of several helper subclasses, and you want to localize the knowledge of which helper subclass is the delegate.

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// Modified from the previous example
public class FactoryMethod{
    public static void main(String[] args){
        Factory factoryA = new FactoryA();
        
        // Product productA = Factory.createProduct("A");
        Product productA = factoryA.createProduct();
        productA.info();
        // ...
    }
}

// Abstract class changed to Interface
interface Product{
    public void info();
}

// Inherit changed to Implement
class ProductA implements Product{
    @Override
    public void info(){
        System.out.println("A");
    }
}

class ProductB implements Product{
    @Override
    public void info(){
        System.out.println("B");
    }
}

// Concrete class changed to Interface
interface Factory{
    public Product createProduct();
}

// Added interface implementations
class FactoryA implements Factory{
    @Override
    public Product createProduct(){
        return new ProductA();
    }
}

class FactoryB implements Factory{
    @Override
    public Product createProduct(){
        return new ProductB();
    }
}

Abstract Factory Pattern

Abstract Factory Pattern - An Object Creational Pattern.

Intent

Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

Structure

Abstract Factory Pattern

Roles:

  • AbstractFactory: Declares an interface for operations that create abstract product objects.
  • ConcreteFactory: Implements the operations to create concrete product objects.
  • AbstractProduct: Declares an interface for a type of product object.
  • ConcreteProduct: Defines a product object to be created by the corresponding concrete factory; implements the AbstractProduct interface.
  • Client: Uses only interfaces declared by AbstractFactory and AbstractProduct classes.

Applicability

Use the Abstract Factory pattern when:

  • A system should be independent of how its products are created, composed, and represented.
  • A system should be configured with one of multiple families of products.
  • A family of related product objects is designed to be used together, and you need to enforce this constraint.
  • You want to provide a class library of products, and you want to reveal just their interfaces, not their implementations.

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
public class AbstractFactory{
    public static void main(String[] args){
        Factory factory1 = new Factory1();
        
        ProductA productA = factory1.createProductA();
        productA.info();
        // ...
    }
}

interface ProductA{
    public void info();
}

class ProductA1 implements ProductA{
    @Override
    public void info(){
        System.out.println("A1");
    }
}

class ProductA2 implements ProductA{
    @Override
    public void info(){
        System.out.println("A2");
    }
}

interface ProductB{
    public void info();
}

class ProductB1 implements ProductB{
    @Override
    public void info(){
        System.out.println("B1");
    }
}

class ProductB2 implements ProductB{
    @Override
    public void info(){
        System.out.println("B2");
    }
}

interface Factory{
    public ProductA createProductA();
    public ProductB createProductB();
}

class Factory1 implements Factory{
    @Override
    public ProductA createProductA(){
        return new ProductA1();
    }
    
    @Override
    public ProductB createProductB(){
        return new ProductB1();
    }
}

class Factory2 implements Factory{
    @Override
    public ProductA createProductA(){
        return new ProductA2();
    }
    
    @Override
    public ProductB createProductB(){
        return new ProductB2();
    }
}