Factory Method (Creational)
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.
Problem
Section titled βProblemβImagine that youβre creating a logistics management application. The first version of your app can only handle transportation by trucks, so the bulk of your code lives inside the Truck class.
After a while, your app becomes pretty popular. Each day you receive dozens of requests from sea transportation companies to incorporate sea logistics into the app.
Great news, right? But what about the code? At present, most of your code is coupled to the Truck class. Adding Ships into the app would require making changes to the entire codebase. Moreover, if later you decide to add another type of transportation to the app, you will probably need to make all of these changes again.
As a result, you will end up with some pretty nasty code, riddled with conditionals that switch the appβs behavior depending on the class of transportation objects.
Solution
Section titled βSolutionβThe Factory Method pattern suggests that you replace direct object construction calls (using the new operator) with calls to a special factory method. Donβt worry: the objects are still created via the new operator, but itβs being called from within the factory method. Objects returned by a factory method are often referred to as products.
At first glance, this change may look pointless: we just moved the constructor call from one part of the program to another. However, consider this: now you can override the factory method in a subclass and change the class of products being created by the method.
Thereβs a slight limitation though: subclasses may return different types of products only if these products have a common base class or interface. Also, the factory method in the base class should have its return type declared as this interface.
Real-World Analogy
Section titled βReal-World AnalogyβImagine a large delivery company. In the beginning, they only deliver mail using bikes. As the company grows, they start using trucks and eventually planes.
The βFactoryβ here is the Dispatcher. When a package needs to be sent, the dispatcher doesnβt just grab a random vehicle; they follow a process (the Factory Method) to assign the right βProductβ (Bike, Truck, or Plane) based on the destination and size, without the customer needing to know which specific vehicle is carrying their letter.
Structure
Section titled βStructureβ- Product declares the interface, which is common to all objects that can be produced by the creator and its subclasses.
- Concrete Products are different implementations of the product interface.
- Creator class declares the factory method that returns new product objects. Itβs important that the return type of this method matches the product interface.
- Concrete Creators override the base factory method so it returns a different type of product.
Structure (Class Diagram)
Section titled βStructure (Class Diagram)βclassDiagram
class Creator {
<<abstract>>
+someOperation()
+createProduct() Product*
}
class ConcreteCreatorA {
+createProduct() Product
}
class ConcreteCreatorB {
+createProduct() Product
}
class Product {
<<interface>>
+doStuff()
}
class ConcreteProductA {
+doStuff()
}
class ConcreteProductB {
+doStuff()
}
Creator <|-- ConcreteCreatorA
Creator <|-- ConcreteCreatorB
Product <|.. ConcreteProductA
Product <|.. ConcreteProductB
ConcreteCreatorA ..> ConcreteProductA : creates
ConcreteCreatorB ..> ConcreteProductB : creates
Pseudocode
Section titled βPseudocodeβ# The product interface declares the operations that all# concrete products must implement.interface Transport: method deliver()
# Concrete products provide various implementations of the# product interface.class Truck implements Transport: method deliver(): print("Deliver by land in a box.")
class Ship implements Transport: method deliver(): print("Deliver by sea in a container.")
# The Creator class declares the factory method that is# supposed to return an object of a Product class.abstract class Logistics: abstract method createTransport(): Transport
# Note that the Creator's primary responsibility isn't # creating products. It usually contains some core # business logic that relies on Product objects. method planDelivery(): Transport t = createTransport() t.deliver()
# Concrete creators override the factory method to change# the resulting product's type.class RoadLogistics extends Logistics: method createTransport(): return new Truck()
class SeaLogistics extends Logistics: method createTransport(): return new Ship()Applicability
Section titled βApplicabilityβ- Use the Factory Method when you donβt know beforehand the exact types and dependencies of the objects your code should work with. The Factory Method separates product construction code from the code that actually uses the product. Therefore itβs easier to extend the product construction code independently from the rest of the code.
- Use the Factory Method when you want to provide users of your library or framework with a way to extend its internal components. Inheritance is probably the easiest way to extend the default behavior of a library or framework. But how would the framework recognize that your subclass should be used instead of a standard component? The solution is to reduce the code that constructs components across the framework into a single factory method and let anyone override this method in addition to extending the component itself.
- Use the Factory Method when you want to save system resources by reusing existing objects instead of rebuilding them each time. This is common when dealing with large, resource-intensive objects like database connections, file systems, and network resources.
How to Implement
Section titled βHow to Implementβ- Make all products follow the same interface. This interface should declare methods that make sense in every product.
- Add an empty factory method inside the creator class. The return type of the method should match the common product interface.
- In the creatorβs code, find all references to product constructors. One by one, replace them with calls to the factory method, while extracting the product creation code into the factory method.
- Now, create a set of creator subclasses for each type of product listed in the factory method. Override the factory method in the subclasses and extract the appropriate bits of construction code from the base method.
Pros and Cons
Section titled βPros and ConsβPros:
- You avoid tight coupling between the creator and the concrete products.
- Single Responsibility Principle. You can move the product creation code into one place in the program, making the code easier to support.
- Open/Closed Principle. You can introduce new types of products into the program without breaking existing client code.
Cons:
- The code may become more complicated since you need to introduce a lot of new subclasses to implement the pattern. The best-case scenario is when youβre introducing the pattern into an existing hierarchy of creator classes.
Relations with other Design Patterns
Section titled βRelations with other Design Patternsβ- Many designs start by using Factory Method (less complicated and more customizable via subclasses) and evolve toward Abstract Factory, Prototype, or Builder (more flexible, but more complicated).
- Abstract Factory classes are often based on a set of Factory Methods, but you can also use Prototype to compose the methods on these classes.
- Factory Method is a specialization of Template Method. At the same time, a Factory Method may serve as a step in a large Template Method.
Code Examples
Section titled βCode ExamplesβCode Examples (C#)
Section titled βCode Examples (C#)β// Productpublic interface IProduct{ void Execute();}
// Concrete Productspublic class ProductA : IProduct{ public void Execute() => Console.WriteLine("Product A");}
public class ProductB : IProduct{ public void Execute() => Console.WriteLine("Product B");}
// Creatorpublic abstract class Creator{ public abstract IProduct FactoryMethod();
public void Run() { var product = FactoryMethod(); product.Execute(); }}
// Concrete Creatorspublic class CreatorA : Creator{ public override IProduct FactoryMethod() => new ProductA();}
public class CreatorB : Creator{ public override IProduct FactoryMethod() => new ProductB();}
// Usageclass Program{ static void Main() { Creator creator = new CreatorA(); creator.Run();
creator = new CreatorB(); creator.Run(); }}Code Examples (Python)
Section titled βCode Examples (Python)βfrom __future__ import annotationsfrom abc import ABC, abstractmethod
class Creator(ABC): @abstractmethod def factory_method(self): pass
def some_operation(self) -> str: product = self.factory_method() result = f"Creator: The same creator's code has just worked with {product.operation()}" return result
class ConcreteCreator1(Creator): def factory_method(self) -> Product: return ConcreteProduct1()
class ConcreteCreator2(Creator): def factory_method(self) -> Product: return ConcreteProduct2()
class Product(ABC): @abstractmethod def operation(self) -> str: pass
class ConcreteProduct1(Product): def operation(self) -> str: return "{Result of the ConcreteProduct1}"
class ConcreteProduct2(Product): def operation(self) -> str: return "{Result of the ConcreteProduct2}"
def client_code(creator: Creator) -> None: print(f"Client: I'm not aware of the creator's class, but it still works.\\n" f"{creator.some_operation()}", end="")
if __name__ == "__main__": print("App: Launched with the ConcreteCreator1.") client_code(ConcreteCreator1()) print("\\n") print("App: Launched with the ConcreteCreator2.") client_code(ConcreteCreator2())Code Examples (C++)
Section titled βCode Examples (C++)β#include <iostream>#include <memory>
// Productclass IProduct {public: virtual ~IProduct() = default; virtual void Execute() = 0;};
// Concrete Productsclass ProductA : public IProduct {public: void Execute() override { std::cout << "Product A" << std::endl; }};
class ProductB : public IProduct {public: void Execute() override { std::cout << "Product B" << std::endl; }};
// Creatorclass Creator {public: virtual ~Creator() = default;
virtual std::unique_ptr<IProduct> FactoryMethod() = 0;
void Run() { auto product = FactoryMethod(); product->Execute(); }};
// Concrete Creatorsclass CreatorA : public Creator {public: std::unique_ptr<IProduct> FactoryMethod() override { return std::make_unique<ProductA>(); }};
class CreatorB : public Creator {public: std::unique_ptr<IProduct> FactoryMethod() override { return std::make_unique<ProductB>(); }};
// Usageint main() { std::unique_ptr<Creator> creator = std::make_unique<CreatorA>(); creator->Run();
creator = std::make_unique<CreatorB>(); creator->Run();
return 0;}Code Examples (Java)
Section titled βCode Examples (Java)β// Product interfacepublic interface IProduct { void execute();}
// Concrete Productspublic class ProductA implements IProduct { @Override public void execute() { System.out.println("Product A"); }}
public class ProductB implements IProduct { @Override public void execute() { System.out.println("Product B"); }}
// Creator (Abstract)public abstract class Creator {
public abstract IProduct factoryMethod();
public void run() { IProduct product = factoryMethod(); product.execute(); }}
// Concrete Creatorspublic class CreatorA extends Creator { @Override public IProduct factoryMethod() { return new ProductA(); }}
public class CreatorB extends Creator { @Override public IProduct factoryMethod() { return new ProductB(); }}
// Usagepublic class Program { public static void main(String[] args) { Creator creator = new CreatorA(); creator.run();
creator = new CreatorB(); creator.run(); }}Code Examples (JavaScript)
Section titled βCode Examples (JavaScript)β// Product Base βInterfaceβ// JavaScript doesnβt enforce interfaces, but we can simulate the contract:class IProduct { execute() { throw new Error("execute() must be implemented"); }}
// Concrete Productsclass ProductA extends IProduct { execute() { console.log("Product A"); }}
class ProductB extends IProduct { execute() { console.log("Product B"); }}
// Creator (Abstract)class Creator { factoryMethod() { throw new Error("factoryMethod() must be implemented"); }
run() { const product = this.factoryMethod(); product.execute(); }}
// Concrete Creatorsclass CreatorA extends Creator { factoryMethod() { return new ProductA(); }}
class CreatorB extends Creator { factoryMethod() { return new ProductB(); }}
// Usageconst creator1 = new CreatorA();creator1.run();
const creator2 = new CreatorB();creator2.run();Code Examples (Visual Basic)
Section titled βCode Examples (Visual Basic)β' ProductPublic Interface IProduct Sub Execute()End Interface
' Concrete ProductsPublic Class ProductA Implements IProduct
Public Sub Execute() Implements IProduct.Execute Console.WriteLine("Product A") End SubEnd Class
Public Class ProductB Implements IProduct
Public Sub Execute() Implements IProduct.Execute Console.WriteLine("Product B") End SubEnd Class
' CreatorPublic MustInherit Class Creator Public MustOverride Function FactoryMethod() As IProduct
Public Sub Run() Dim product = FactoryMethod() product.Execute() End SubEnd Class
' Concrete CreatorsPublic Class CreatorA Inherits Creator
Public Overrides Function FactoryMethod() As IProduct Return New ProductA() End FunctionEnd Class
Public Class CreatorB Inherits Creator
Public Overrides Function FactoryMethod() As IProduct Return New ProductB() End FunctionEnd Class
' UsageModule Program Sub Main() Dim creator As Creator = New CreatorA() creator.Run()
creator = New CreatorB() creator.Run() End SubEnd ModuleCode Examples (Rust)
Section titled βCode Examples (Rust)β// Producttrait Product { fn execute(&self);}
// Concrete Productsstruct ProductA;struct ProductB;
impl Product for ProductA { fn execute(&self) { println!("Product A"); }}
impl Product for ProductB { fn execute(&self) { println!("Product B"); }}
// Creatortrait Creator { fn factory_method(&self) -> Box<dyn Product>;
fn run(&self) { let product = self.factory_method(); product.execute(); }}
// Concrete Creatorsstruct CreatorA;struct CreatorB;
impl Creator for CreatorA { fn factory_method(&self) -> Box<dyn Product> { Box::new(ProductA) }}
impl Creator for CreatorB { fn factory_method(&self) -> Box<dyn Product> { Box::new(ProductB) }}
// Usagefn main() { let creator: Box<dyn Creator> = Box::new(CreatorA); creator.run();
let creator: Box<dyn Creator> = Box::new(CreatorB); creator.run();}Code Examples (PHP)
Section titled βCode Examples (PHP)β<?php
// Productinterface IProduct{ public function execute(): void;}
// Concrete Productsclass ProductA implements IProduct{ public function execute(): void { echo "Product A\n"; }}
class ProductB implements IProduct{ public function execute(): void { echo "Product B\n"; }}
// Creatorabstract class Creator{ abstract public function factoryMethod(): IProduct;
public function run(): void { $product = $this->factoryMethod(); $product->execute(); }}
// Concrete Creatorsclass CreatorA extends Creator{ public function factoryMethod(): IProduct { return new ProductA(); }}
class CreatorB extends Creator{ public function factoryMethod(): IProduct { return new ProductB(); }}
// Usage$creator = new CreatorA();$creator->run();
$creator = new CreatorB();$creator->run();Code Examples (Go)
Section titled βCode Examples (Go)βpackage main
import ( "fmt")
// Product interfacetype Product interface { Execute()}
// Concrete Productstype ProductA struct{}type ProductB struct{}
func (ProductA) Execute() { fmt.Println("Product A")}
func (ProductB) Execute() { fmt.Println("Product B")}
// Creator interfacetype Creator interface { FactoryMethod() Product}
// Shared behavior (equivalent to Creator.Run())func Run(c Creator) { p := c.FactoryMethod() p.Execute()}
// Concrete Creatorstype CreatorA struct{}type CreatorB struct{}
func (CreatorA) FactoryMethod() Product { return ProductA{}}
func (CreatorB) FactoryMethod() Product { return ProductB{}}
// Usagefunc main() { var creator Creator
creator = CreatorA{} Run(creator)
creator = CreatorB{} Run(creator)}Code Examples (Ruby)
Section titled βCode Examples (Ruby)β# Productclass Productdef execute raise NotImplementedError, "Subclasses must implement execute"endend
# Concrete Productsclass ProductA < Productdef execute puts "Product A"endend
class ProductB < Productdef execute puts "Product B"endend
# Creatorclass Creatordef factory_method raise NotImplementedError, "Subclasses must implement factory_method"end
def run product = factory_method product.executeendend
# Concrete Creatorsclass CreatorA < Creatordef factory_method ProductA.newendend
class CreatorB < Creatordef factory_method ProductB.newendend
# Usagecreator = CreatorA.newcreator.run
creator = CreatorB.newcreator.runCode Examples (Perl)
Section titled βCode Examples (Perl)β#!/usr/bin/perluse strict;use warnings;
############################# Product (Interface-like)############################package Product;sub execute { die "execute() must be implemented by subclass";}
############################# Concrete Products############################package ProductA;our @ISA = ('Product');
sub new { bless {}, shift }
sub execute { print "Product A\n";}
package ProductB;our @ISA = ('Product');
sub new { bless {}, shift }
sub execute { print "Product B\n";}
############################# Creator (Abstract)############################package Creator;
sub factory_method { die "factory_method() must be implemented by subclass";}
sub run { my ($self) = @_; my $product = $self->factory_method(); $product->execute();}
############################# Concrete Creators############################package CreatorA;our @ISA = ('Creator');
sub new { bless {}, shift }
sub factory_method { return ProductA->new();}
package CreatorB;our @ISA = ('Creator');
sub new { bless {}, shift }
sub factory_method { return ProductB->new();}
############################# Usage############################package main;
my $creator = CreatorA->new();$creator->run();
$creator = CreatorB->new();$creator->run();Code Examples (TypeScript)
Section titled βCode Examples (TypeScript)β// Product Interfaceinterface IProduct { execute(): void;}
// Concrete Productsclass ProductA implements IProduct { execute(): void { console.log("Product A"); }}
class ProductB implements IProduct { execute(): void { console.log("Product B"); }}
// Creator (Abstract)abstract class Creator { abstract factoryMethod(): IProduct;
run(): void { const product = this.factoryMethod(); product.execute(); }}
// Concrete Creatorsclass CreatorA extends Creator { factoryMethod(): IProduct { return new ProductA(); }}
class CreatorB extends Creator { factoryMethod(): IProduct { return new ProductB(); }}
// Usageconst creator1: Creator = new CreatorA();creator1.run();
const creator2: Creator = new CreatorB();creator2.run();