Factory Method Design Pattern in Go: A Comprehensive Guide

Explore the Factory Method design pattern in Go, its implementation, use cases, and best practices for creating flexible and scalable software architectures.

2.1.3 Factory Method

The Factory Method is a creational design pattern that provides an interface for creating objects in a superclass but allows subclasses to alter the type of objects that will be created. This pattern is particularly useful in scenarios where a class cannot anticipate the class of objects it needs to create or when it wants to delegate the responsibility of object instantiation to subclasses.

Understand the Intent

The primary intent of the Factory Method pattern is to define an interface for creating an object, but let subclasses decide which class to instantiate. This approach promotes loose coupling by reducing the dependency of the code on specific classes and allows for more flexible and scalable software design.

Implementation Steps

To implement the Factory Method pattern in Go, follow these steps:

  1. Define a Creator Interface or Struct with a Factory Method:

    • The creator interface or struct declares the factory method that returns an object of a product interface.
  2. Implement Concrete Creators:

    • Concrete creators override the factory method to produce different products. Each concrete creator corresponds to a specific product type.
  3. Define Product Interfaces and Concrete Product Types:

    • The product interface defines the operations that all concrete products must implement. Concrete products are the different implementations of the product interface.

Use Cases

The Factory Method pattern is applicable in the following scenarios:

  • When a class cannot anticipate the class of objects it needs to create.
  • When a class wants its subclasses to specify the objects it creates.
  • To delegate the responsibility of object instantiation to subclasses, promoting flexibility and scalability.

Example in Go

Let’s illustrate the Factory Method pattern with an example of a logger that creates different log output objects.

 1package main
 2
 3import (
 4    "fmt"
 5)
 6
 7// Logger is the product interface
 8type Logger interface {
 9    Log(message string)
10}
11
12// ConsoleLogger is a concrete product
13type ConsoleLogger struct{}
14
15func (c *ConsoleLogger) Log(message string) {
16    fmt.Println("Console log:", message)
17}
18
19// FileLogger is another concrete product
20type FileLogger struct{}
21
22func (f *FileLogger) Log(message string) {
23    fmt.Println("File log:", message)
24}
25
26// LoggerFactory is the creator interface
27type LoggerFactory interface {
28    CreateLogger() Logger
29}
30
31// ConsoleLoggerFactory is a concrete creator
32type ConsoleLoggerFactory struct{}
33
34func (c *ConsoleLoggerFactory) CreateLogger() Logger {
35    return &ConsoleLogger{}
36}
37
38// FileLoggerFactory is another concrete creator
39type FileLoggerFactory struct{}
40
41func (f *FileLoggerFactory) CreateLogger() Logger {
42    return &FileLogger{}
43}
44
45func main() {
46    var factory LoggerFactory
47
48    // Use ConsoleLoggerFactory to create a ConsoleLogger
49    factory = &ConsoleLoggerFactory{}
50    logger := factory.CreateLogger()
51    logger.Log("Hello, Console!")
52
53    // Use FileLoggerFactory to create a FileLogger
54    factory = &FileLoggerFactory{}
55    logger = factory.CreateLogger()
56    logger.Log("Hello, File!")
57}

In this example, we define a Logger interface with a Log method. The ConsoleLogger and FileLogger structs implement this interface. The LoggerFactory interface declares a CreateLogger method, which is implemented by ConsoleLoggerFactory and FileLoggerFactory to create instances of ConsoleLogger and FileLogger, respectively.

Best Practices

  • Keep the Creator and Product Interfaces Minimal and Focused: Ensure that interfaces are concise and only include methods that are essential for the pattern’s operation.
  • Centralize Instantiation Logic: Use the factory method to handle the instantiation logic centrally, promoting consistency and reducing duplication.
  • Encapsulate Object Creation: By encapsulating object creation, you can easily extend the system with new product types without modifying existing code.

Advantages and Disadvantages

Advantages:

  • Flexibility: Allows for easy extension of the system with new product types.
  • Decoupling: Reduces dependency on specific classes, promoting loose coupling.
  • Single Responsibility Principle: Separates the responsibility of object creation from the main logic.

Disadvantages:

  • Complexity: Can introduce additional complexity due to the increased number of classes and interfaces.
  • Overhead: May lead to unnecessary overhead if not used judiciously, especially in simple scenarios.

Comparisons

The Factory Method pattern is often compared with the Abstract Factory pattern. While both patterns deal with object creation, the Factory Method focuses on a single product, whereas the Abstract Factory is concerned with creating families of related products.

Conclusion

The Factory Method pattern is a powerful tool for creating flexible and scalable software architectures. By delegating object creation to subclasses, it promotes loose coupling and adherence to the Single Responsibility Principle. When implemented correctly, it can significantly enhance the maintainability and extensibility of your Go applications.

Quiz Time!

Loading quiz…
Revised on Thursday, April 23, 2026