072
creational GOF

Factory Method

Reference Wikipedia ↗
Factory Method — class diagram
Plate 072 class diagram

The Factory Method pattern is a creational design pattern that provides an interface for creating objects, but lets subclasses decide which class to instantiate. It defines a factory method, an operation that returns an object of a product class. Rather than directly instantiating concrete products, the client code calls this factory method within a creator class, and the creator’s subclasses override the factory method to return different types of products. This promotes loose coupling between the creator and the concrete products.

Usage

The Factory Method pattern is commonly used when:

  • A class can’t anticipate the class of objects it must create.
  • A class wants its subclasses to specify the objects it creates.
  • The creation of objects requires complex logic or relies on configuration data that is only available at runtime.
  • You want to centralize object creation logic to ensure consistency and maintainability.

Examples

  1. Java’s JDBC Framework: The java.sql.Connection interface’s newConnection() method (within its subclasses like DriverManager) serves as a factory method. It allows different database drivers (MySQL, PostgreSQL, Oracle) to provide their own specific connection implementations without the client code needing to know the concrete class.

  2. Django’s Model Managers: In Django, model managers provide a way to encapsulate database query logic. The create() method on a manager acts as a factory method. Different managers can be defined for a model, each creating instances with different default values or applying different validation rules, but clients always call create() on the manager without knowing the specifics of how the object is constructed.

  3. Configuration Parsing Libraries: Many configuration parsing libraries (e.g., for XML, YAML, JSON) use a factory method approach. A generic parser might have a method to create configuration objects, while specific parsers for different configuration formats implement that method to create the appropriate object type.

Specimens

15 implementations
Specimen 072.01 Dart View specimen ↗

The Factory Method pattern is a creational pattern that lets a class defer instantiation to subclasses. It defines an interface for creating an object, but lets subclasses alter the type of objects that will be created. This promotes loose coupling and extensibility, allowing you to add new product types without modifying the core creating class.

This Dart example showcases a Document abstract class and concrete implementations MarkdownDocument and HtmlDocument. The DocumentFactory class uses a factory method, createDocument(), to determine which concrete document type to instantiate based on a provided type string. This design is idiomatic Dart as it leverages abstract classes and factory constructors to manage object creation and maintain flexibility, a common approach in Dart’s object-oriented structure.

abstract class Document {
  String getContent();
}

class MarkdownDocument implements Document {
  final String content;
  MarkdownDocument(this.content);

  @override
  String getContent() => 'Markdown: $content';
}

class HtmlDocument implements Document {
  final String content;
  HtmlDocument(this.content);

  @override
  String getContent() => 'HTML: $content';
}

class DocumentFactory {
  Document createDocument(String type, String content) {
    switch (type) {
      case 'markdown':
        return MarkdownDocument(content);
      case 'html':
        return HtmlDocument(content);
      default:
        throw ArgumentError('Unsupported document type: $type');
    }
  }
}

void main() {
  final factory = DocumentFactory();

  final markdownDoc = factory.createDocument('markdown', 'This is markdown content.');
  print(markdownDoc.getContent());

  final htmlDoc = factory.createDocument('html', '<h1>This is HTML content.</h1>');
  print(htmlDoc.getContent());

  // Should throw an error
  // factory.createDocument('pdf', 'Some PDF content');
}