Skip to content

Factory method pattern

Quality Score

Overall Score: 9.5/10 ⭐ Outstanding

  • Technical Accuracy: 35/35
  • Code Quality: 24/25
  • Educational Value: 25/25
  • Documentation: 14/15

Last reviewed: July 14, 2026

The factory method pattern is a creational design pattern that provides an interface (a factory) for creating objects (products). Ideally, one factory should be responsible for creating one type of product. It is commonly misunderstood, as just seem inheritance with extra steps. But the main idea is to decouple the code, so the libraries that use it must work with any concrete class. It also allows for easy extension of the codebase by adding new concrete classes (even new concrete classes can be used for mocking in tests). The factory method pattern is used when a class cannot anticipate the type of objects it needs to create. The main benefits of this pattern are:

  • Decoupling: The factory method pattern decouples the client code from the concrete classes that it needs to instantiate, allowing for more flexible and maintainable code.
  • Extensibility: The factory method pattern allows for easy extension of the codebase by adding new concrete classes without modifying the existing code.
  • Single Responsibility Principle: The factory method pattern allows for the separation of object creation from the business logic, allowing for a single responsibility for each class.

The factory method pattern is composed of four main components:

Product Interface

Defines the common interface for all supported products that can be created by the factory method class.

src.advanced.factory_method_pattern.Exporter

Bases: ABC

Abstract base class for data exporters.

This defines the common interface that all exporters must implement. The Factory Method pattern allows us to work with this interface without knowing the concrete type.

Source code in src/advanced/factory_method_pattern/factory_method.py
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Exporter(ABC):
    """Abstract base class for data exporters.

    This defines the common interface that all exporters must implement.
    The Factory Method pattern allows us to work with this interface
    without knowing the concrete type.
    """

    @abstractmethod
    def export(self, data: dict) -> str:
        """Export the data in a specific format.

        Args:
            data: The data to be exported.

        Returns:
            The exported data as a string.
        """
        pass

Concrete Product

Implements the behavior associated with a product.

src.advanced.factory_method_pattern.JSONExporter

Bases: Exporter

Concrete exporter for JSON format.

This exporter can be configured with indentation preferences.

Source code in src/advanced/factory_method_pattern/factory_method.py
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
class JSONExporter(Exporter):
    """Concrete exporter for JSON format.

    This exporter can be configured with indentation preferences.
    """

    def __init__(self, indent: Optional[int] = 4) -> None:
        """Initialize the JSON exporter with an optional indentation level.

        Args:
            indent: The number of spaces to use for indentation
            in the JSON output. If None, the output will be compact.
            Defaults to 4.
        """
        self.indent = indent

    def export(self, data: dict) -> str:
        """Export the data in JSON format.

        Args:
            data: The data to be exported.

        Returns:
            JSON formatted string.

        """
        return json.dumps(data, indent=self.indent)

src.advanced.factory_method_pattern.YamlExporter

Bases: Exporter

Concrete exporter for YAML format.

This exporter can be configured with flow style preferences.

Source code in src/advanced/factory_method_pattern/factory_method.py
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
class YamlExporter(Exporter):
    """Concrete exporter for YAML format.

    This exporter can be configured with flow style preferences.
    """

    def __init__(self, default_flow_style: Optional[bool] = False) -> None:
        """Initialize the YAML exporter with an optional flow style.

        Args:
            default_flow_style: If True, the output will be in default inline
            style.
            If False, the output will be in block style (multiline).
            Defaults to False.
        """
        self.default_flow_style = default_flow_style

    def export(self, data: dict) -> str:
        """Export the data in YAML format.

        Args:
            data: The data to be exported.

        Returns:
            YAML formatted string.

        """
        return yaml.dump(data, default_flow_style=self.default_flow_style)

Creator Interface

Defines the common interface for all supported creators that can create products.

src.advanced.factory_method_pattern.ExporterFactory

Bases: ABC

Abstract base class for exporter factories.

This is the "Creator" in the Factory Method pattern. It defines the factory method that subclasses must implement.

The key insight: code that receives an ExporterFactory doesn't know or care which concrete exporter will be created. This enables dependency injection and makes code more flexible.

Source code in src/advanced/factory_method_pattern/factory_method.py
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
class ExporterFactory(ABC):
    """Abstract base class for exporter factories.

    This is the "Creator" in the Factory Method pattern. It defines
    the factory method that subclasses must implement.

    The key insight: code that receives an ExporterFactory doesn't
    know or care which concrete exporter will be created. This
    enables dependency injection and makes code more flexible.
    """

    @abstractmethod
    def create_exporter(self) -> Exporter:
        """Create an exporter instance.

        Returns:
            An instance of a concrete exporter.
        """
        pass

Concrete Creators

Implements the behavior associated with a creator that can create products.

src.advanced.factory_method_pattern.JSONExporterFactory

Bases: ExporterFactory

Concrete factory for creating JSON exporters.

This factory encapsulates the creation logic for JSON exporters, including their configuration.

Source code in src/advanced/factory_method_pattern/factory_method.py
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
class JSONExporterFactory(ExporterFactory):
    """Concrete factory for creating JSON exporters.

    This factory encapsulates the creation logic for JSON exporters,
    including their configuration.
    """

    def __init__(self, indent: Optional[int] = 4) -> None:
        """Initialize the JSON exporter factory.

        Args:
            indent: The number of spaces to use for indentation
            in the JSON output. If None, the output will be compact.
            Defaults to 4.
        """
        self.indent = indent

    def create_exporter(self) -> Exporter:
        """Create a JSON exporter with the configured indentation.

        Returns:
            An instance of JSONExporter.

        """
        return JSONExporter(indent=self.indent)

src.advanced.factory_method_pattern.YamlExporterFactory

Bases: ExporterFactory

Concrete factory for creating YAML exporters.

This factory encapsulates the creation logic for YAML exporters, including their configuration.

Source code in src/advanced/factory_method_pattern/factory_method.py
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
class YamlExporterFactory(ExporterFactory):
    """Concrete factory for creating YAML exporters.

    This factory encapsulates the creation logic for YAML exporters,
    including their configuration.
    """

    def __init__(self, default_flow_style: Optional[bool] = False) -> None:
        """Initialize the YAML exporter factory with an optional flow style.

        Args:
            default_flow_style: If True, the output will be in default inline
            style.
            If False, the output will be in block style (multiline).
            Defaults to False.
        """
        self.default_flow_style = default_flow_style

    def create_exporter(self) -> Exporter:
        """Create a YAML exporter with the configured flow style.

        Returns:
            An instance of YamlExporter.

        """
        return YamlExporter(default_flow_style=self.default_flow_style)

This simple scenario seems overkill, but in a scenario where the code does not know the concrete classes that will be used, it is easy to create this pattern to start the work. Additionally, you can add new exporters without changing the code that uses the factory.

src.advanced.factory_method_pattern.DataExportService

Service that exports data using a factory pattern.

This class demonstrates the key value of the Factory Method pattern: it receives a factory but doesn't know which concrete factory it is. This enables dependency injection, making the code flexible and testable.

The service can work with ANY factory that implements ExporterFactory, making it easy to: - Change export formats without modifying this code - Add new exporters without modifying this code - Test with mock factories

Source code in src/advanced/factory_method_pattern/factory_method.py
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
class DataExportService:
    """Service that exports data using a factory pattern.

    This class demonstrates the key value of the Factory Method pattern:
    it receives a factory but doesn't know which concrete factory it is.
    This enables dependency injection, making the code flexible and testable.

    The service can work with ANY factory that implements ExporterFactory,
    making it easy to:
    - Change export formats without modifying this code
    - Add new exporters without modifying this code
    - Test with mock factories
    """

    def __init__(self, factory: ExporterFactory):
        """Initialize the data export service with a factory.

        Args:
            factory: The factory to use for creating exporters.
                This is dependency injection - we don't know the concrete type!
        """
        self.factory = factory

    def export_user_report(self, users: list[dict]) -> str:
        """Export a user report using the provided factory.

        Notice: This method has NO IDEA which format will be used!
        The factory determines the concrete exporter type.

        Args:
            users: List of user dictionaries to export.

        Returns:
            The exported data as a string in the format determined
            by the factory.

        """
        exporter = self.factory.create_exporter()
        return exporter.export({"users": users})

You can even combine the factory method pattern with the strategy pattern and singleton to create a more complex, reusable and flexible design.

Abstract factories are a more complex version of the factory method pattern, where a single factory can create multiple types of related products. An abstract factory is a factory of factories, where each concrete factory is responsible for creating a family of related products, so there are no mistakes between the products created by different factories.