Card 03/ 09
Factory Method Template in Python, Java and TypeScript
The pure form with the Gang of Four's names and no domain, one participant at a time.
The Factory Method template is the pattern in its pure form, with the participant names from the class diagram and no domain to distract from the structure. This card builds it one participant at a time in Python, and the tabs then give the complete program in Python, Java and TypeScript, each with its output.
Building the template one participant at a time
Product
The interface every created object shares. In Python it is an abstract base class with one abstract method.
class Product(ABC):
@abstractmethod
def operation(self) -> str: ...Concrete products
Two classes implement it, each answering operation in its own way.
class ConcreteProductA(Product):
def operation(self) -> str:
return "ConcreteProductA"Creator
The creator declares the factory method and uses it. some_operation works with whatever the factory method returns, through the Product type alone.
class Creator(ABC):
@abstractmethod
def factory_method(self) -> Product: ...
def some_operation(self) -> str:
product = self.factory_method()
return f"Creator worked with {product.operation()}"Concrete creators
Each subclass overrides the factory method and names one concrete product. This is the only place a concrete product class is named.
class ConcreteCreatorA(Creator):
def factory_method(self) -> Product:
return ConcreteProductA()The complete template
from abc import ABC, abstractmethod
class Product(ABC):
@abstractmethod
def operation(self) -> str: ...
class ConcreteProductA(Product):
def operation(self) -> str:
return "ConcreteProductA"
class ConcreteProductB(Product):
def operation(self) -> str:
return "ConcreteProductB"
class Creator(ABC):
@abstractmethod
def factory_method(self) -> Product: ...
def some_operation(self) -> str:
product = self.factory_method()
return f"Creator worked with {product.operation()}"
class ConcreteCreatorA(Creator):
def factory_method(self) -> Product:
return ConcreteProductA()
class ConcreteCreatorB(Creator):
def factory_method(self) -> Product:
return ConcreteProductB()
for creator in [ConcreteCreatorA(), ConcreteCreatorB()]:
print(creator.some_operation())Creator worked with ConcreteProductA
Creator worked with ConcreteProductBimport java.util.List;
public class FmTemplate {
public static void main(String[] args) {
for (Creator creator : List.of(new ConcreteCreatorA(), new ConcreteCreatorB())) {
System.out.println(creator.someOperation());
}
}
}
interface Product {
String operation();
}
class ConcreteProductA implements Product {
public String operation() {
return "ConcreteProductA";
}
}
class ConcreteProductB implements Product {
public String operation() {
return "ConcreteProductB";
}
}
abstract class Creator {
protected abstract Product factoryMethod();
public String someOperation() {
Product product = factoryMethod();
return "Creator worked with " + product.operation();
}
}
class ConcreteCreatorA extends Creator {
protected Product factoryMethod() {
return new ConcreteProductA();
}
}
class ConcreteCreatorB extends Creator {
protected Product factoryMethod() {
return new ConcreteProductB();
}
}Creator worked with ConcreteProductA
Creator worked with ConcreteProductBinterface Product {
operation(): string;
}
class ConcreteProductA implements Product {
operation(): string {
return "ConcreteProductA";
}
}
class ConcreteProductB implements Product {
operation(): string {
return "ConcreteProductB";
}
}
abstract class Creator {
protected abstract factoryMethod(): Product;
someOperation(): string {
const product = this.factoryMethod();
return `Creator worked with ${product.operation()}`;
}
}
class ConcreteCreatorA extends Creator {
protected factoryMethod(): Product {
return new ConcreteProductA();
}
}
class ConcreteCreatorB extends Creator {
protected factoryMethod(): Product {
return new ConcreteProductB();
}
}
for (const creator of [new ConcreteCreatorA(), new ConcreteCreatorB()]) {
console.log(creator.someOperation());
}Creator worked with ConcreteProductA
Creator worked with ConcreteProductBThe highlighted lines are the whole pattern: the factory method is declared once, called once inside the creator, and overridden once per concrete creator. Everything else is ordinary classes.
The loop at the end holds two creators, and some_operation gives a different answer for each without changing: the shared code is written once, and the class it works with is chosen by which creator you have.
← → move through sections and cards