Abstract Factory (Creational)
Abstract Factory is a creational design pattern that lets you produce families of related objects without specifying their concrete classes.
Problem
Section titled βProblemβImagine youβre creating a furniture shop simulator. Your code consists of classes that represent:
- A family of related products, say:
Chair+Sofa+CoffeeTable. - Several variants of this family. For example, products
Chair+Sofa+CoffeeTableare available in these variants:Modern,Victorian,ArtDeco.
You need a way to create individual furniture objects so that they match other objects of the same family. Customers get quite mad when they receive a Modern sofa with a Victorian chair.
Also, you donβt want to change existing code when adding new products or families of products to the program. Furniture vendors update their catalogs very often, and you wouldnβt want to change the core code each time it happens.
Solution
Section titled βSolutionβThe first thing the Abstract Factory pattern suggests is to explicitly declare interfaces for each distinct product of the product family (e.g., chair, sofa or coffee table). Then you can make all variants of products follow those interfaces. For example, all chair variants can implement the Chair interface; all coffee table variants can implement the CoffeeTable interface, and so on.
The next move is to declare the Abstract Factoryβan interface with a list of creation methods for all products that are part of the product family (for example, createChair, createSofa and createCoffeeTable). These methods must return abstract product types represented by the interfaces we extracted previously: Chair, Sofa, CoffeeTable and so on.
Now, how about the product variants? For each variant of a product family, we create a separate factory class based on the AbstractFactory interface. A factory is a class that returns products of a particular kind. For example, the ModernFurnitureFactory can only create ModernChair, ModernSofa and ModernCoffeeTable objects.
The client code has to work with both factories and products through their respective abstract interfaces. This lets you change the type of a factory that you pass to the client code, as well as the product variant that the client code receives, without breaking the actual client code.
Real-World Analogy
Section titled βReal-World AnalogyβThink of a car manufacturing plant. The Abstract Factory is the general blueprint for a βCar Factory.β
A Concrete Factory would be the βElectric Car Factoryβ or the βGasoline Car Factory.β
- The Electric Factory produces βElectric Enginesβ and βCharging Ports.β
- The Gasoline Factory produces βInternal Combustion Enginesβ and βFuel Tanks.β
The car assembly line (the client) doesnβt care which factory itβs using; it just knows it needs an βEngineβ and a βFuel System.β As long as the factory provides a compatible set of parts, the car can be built.
Structure (Class Diagram)
Section titled βStructure (Class Diagram)βclassDiagram
class AbstractFactory {
<<interface>>
+createProductA() ProductA
+createProductB() ProductB
}
class ConcreteFactory1 {
+createProductA() ProductA
+createProductB() ProductB
}
class ConcreteFactory2 {
+createProductA() ProductA
+createProductB() ProductB
}
class ProductA {
<<interface>>
}
class ProductB {
<<interface>>
}
class ConcreteProductA1
class ConcreteProductA2
class ConcreteProductB1
class ConcreteProductB2
AbstractFactory <|-- ConcreteFactory1
AbstractFactory <|-- ConcreteFactory2
ProductA <|.. ConcreteProductA1
ProductA <|.. ConcreteProductA2
ProductB <|.. ConcreteProductB1
ProductB <|.. ConcreteProductB2
ConcreteFactory1 ..> ConcreteProductA1 : creates
ConcreteFactory1 ..> ConcreteProductB1 : creates
ConcreteFactory2 ..> ConcreteProductA2 : creates
ConcreteFactory2 ..> ConcreteProductB2 : creates
Pseudocode
Section titled βPseudocodeβinterface Chair: method sitOn()
class VictorianChair implements Chair: method sitOn(): print("Sitting on a Victorian chair.")
class ModernChair implements Chair: method sitOn(): print("Sitting on a modern chair.")
interface FurnitureFactory: method createChair(): Chair method createSofa(): Sofa
class VictorianFurnitureFactory implements FurnitureFactory: method createChair(): return new VictorianChair() method createSofa(): return new VictorianSofa()
class ModernFurnitureFactory implements FurnitureFactory: method createChair(): return new ModernChair() method createSofa(): return new ModernSofa()Applicability
Section titled βApplicabilityβ- Use the Abstract Factory when your code needs to work with various families of related products, but you donβt want it to depend on the concrete classes of those products.
- Consider implementing the Abstract Factory when you have a class with a set of Factory Methods that blur its primary responsibility.
How to Implement
Section titled βHow to Implementβ- Map out a matrix of distinct product types versus variants of these products.
- Declare abstract product interfaces for all product types.
- Declare the Abstract Factory interface with a set of creation methods for all abstract products.
- Implement a set of concrete factory classes, one for each product variant.
- Extract the factory initialization code to a central place. It should instantiate one of the concrete factory classes, depending on the application configuration or the current environment.
Pros and Cons
Section titled βPros and ConsβPros:
- You can be sure that the products youβre getting from a factory are compatible with each other.
- You avoid tight coupling between concrete products and client code.
- Single Responsibility Principle.
- Open/Closed Principle.
Cons:
- The code may become more complicated than it should be, since a lot of new interfaces and classes are introduced along with the pattern.
Relations with other Design Patterns
Section titled βRelations with other Design Patternsβ- 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.
- Builder focuses on constructing complex objects step by step. Abstract Factory specializes in creating families of related objects.
Code Examples
Section titled βCode ExamplesβCode Examples (C#)
Section titled βCode Examples (C#)β// Abstract Productspublic interface IButton{ void Paint();}
public interface ICheckbox{ void Render();}
// Concrete Productspublic class WinButton : IButton{ public void Paint() => Console.WriteLine("Windows Button");}
public class MacButton : IButton{ public void Paint() => Console.WriteLine("Mac Button");}
public class WinCheckbox : ICheckbox{ public void Render() => Console.WriteLine("Windows Checkbox");}
public class MacCheckbox : ICheckbox{ public void Render() => Console.WriteLine("Mac Checkbox");}
// Abstract Factorypublic interface IGUIFactory{ IButton CreateButton(); ICheckbox CreateCheckbox();}
// Concrete Factoriespublic class WinFactory : IGUIFactory{ public IButton CreateButton() => new WinButton(); public ICheckbox CreateCheckbox() => new WinCheckbox();}
public class MacFactory : IGUIFactory{ public IButton CreateButton() => new MacButton(); public ICheckbox CreateCheckbox() => new MacCheckbox();}
// Clientpublic class Application{ private readonly IButton _button; private readonly ICheckbox _checkbox;
public Application(IGUIFactory factory) { _button = factory.CreateButton(); _checkbox = factory.CreateCheckbox(); }
public void Render() { _button.Paint(); _checkbox.Render(); }}
// Usageclass Program{ static void Main() { IGUIFactory factory = new WinFactory(); var app = new Application(factory); app.Render(); }}Code Examples (Python)
Section titled βCode Examples (Python)βfrom abc import ABC, abstractmethod
class AbstractFactory(ABC): @abstractmethod def create_product_a(self): pass @abstractmethod def create_product_b(self): pass
class ConcreteFactory1(AbstractFactory): def create_product_a(self): return ConcreteProductA1() def create_product_b(self): return ConcreteProductB1()
class ConcreteFactory2(AbstractFactory): def create_product_a(self): return ConcreteProductA2() def create_product_b(self): return ConcreteProductB2()
class AbstractProductA(ABC): @abstractmethod def useful_function_a(self): pass
class ConcreteProductA1(AbstractProductA): def useful_function_a(self): return "The result of the product A1."
class ConcreteProductA2(AbstractProductA): def useful_function_a(self): return "The result of the product A2."
def client_code(factory: AbstractFactory): product_a = factory.create_product_a() print(f"{product_a.useful_function_a()}")
if __name__ == "__main__": client_code(ConcreteFactory1()) client_code(ConcreteFactory2())Code Examples (C++)
Section titled βCode Examples (C++)β#include <iostream>#include <memory>
// ============================// Abstract Products// ============================class IButton {public: virtual ~IButton() = default; virtual void Paint() = 0;};
class ICheckbox {public: virtual ~ICheckbox() = default; virtual void Render() = 0;};
// ============================// Concrete Products// ============================class WinButton : public IButton {public: void Paint() override { std::cout << "Windows Button" << std::endl; }};
class MacButton : public IButton {public: void Paint() override { std::cout << "Mac Button" << std::endl; }};
class WinCheckbox : public ICheckbox {public: void Render() override { std::cout << "Windows Checkbox" << std::endl; }};
class MacCheckbox : public ICheckbox {public: void Render() override { std::cout << "Mac Checkbox" << std::endl; }};
// ============================// Abstract Factory// ============================class IGUIFactory {public: virtual ~IGUIFactory() = default; virtual std::unique_ptr<IButton> CreateButton() = 0; virtual std::unique_ptr<ICheckbox> CreateCheckbox() = 0;};
// ============================// Concrete Factories// ============================class WinFactory : public IGUIFactory {public: std::unique_ptr<IButton> CreateButton() override { return std::make_unique<WinButton>(); }
std::unique_ptr<ICheckbox> CreateCheckbox() override { return std::make_unique<WinCheckbox>(); }};
class MacFactory : public IGUIFactory {public: std::unique_ptr<IButton> CreateButton() override { return std::make_unique<MacButton>(); }
std::unique_ptr<ICheckbox> CreateCheckbox() override { return std::make_unique<MacCheckbox>(); }};
// ============================// Client// ============================class Application {private: std::unique_ptr<IButton> button; std::unique_ptr<ICheckbox> checkbox;
public: Application(IGUIFactory& factory) { button = factory.CreateButton(); checkbox = factory.CreateCheckbox(); }
void Render() { button->Paint(); checkbox->Render(); }};
// ============================// Usage// ============================int main() { WinFactory factory; Application app(factory); app.Render();
return 0;}Code Examples (Java)
Section titled βCode Examples (Java)β// Abstract Productspublic interface IButton { void paint();}
public interface ICheckbox { void render();}
// Concrete Productspublic class WinButton implements IButton { @Override public void paint() { System.out.println("Windows Button"); }}
public class MacButton implements IButton { @Override public void paint() { System.out.println("Mac Button"); }}
public class WinCheckbox implements ICheckbox { @Override public void render() { System.out.println("Windows Checkbox"); }}
public class MacCheckbox implements ICheckbox { @Override public void render() { System.out.println("Mac Checkbox"); }}
// Abstract Factorypublic interface IGUIFactory { IButton createButton(); ICheckbox createCheckbox();}
// Concrete Factoriespublic class WinFactory implements IGUIFactory { @Override public IButton createButton() { return new WinButton(); }
@Override public ICheckbox createCheckbox() { return new WinCheckbox(); }}
public class MacFactory implements IGUIFactory { @Override public IButton createButton() { return new MacButton(); }
@Override public ICheckbox createCheckbox() { return new MacCheckbox(); }}
// Clientpublic class Application { private final IButton button; private final ICheckbox checkbox;
public Application(IGUIFactory factory) { this.button = factory.createButton(); this.checkbox = factory.createCheckbox(); }
public void render() { button.paint(); checkbox.render(); }}
// Usagepublic class Program { public static void main(String[] args) { IGUIFactory factory = new WinFactory(); Application app = new Application(factory); app.render(); }}Code Examples (JavaScript)
Section titled βCode Examples (JavaScript)β// Abstract Products (simulated interfaces)class IButton { paint() { throw new Error("paint() must be implemented"); }}
class ICheckbox { render() { throw new Error("render() must be implemented"); }}
// Concrete Productsclass WinButton extends IButton { paint() { console.log("Windows Button"); }}
class MacButton extends IButton { paint() { console.log("Mac Button"); }}
class WinCheckbox extends ICheckbox { render() { console.log("Windows Checkbox"); }}
class MacCheckbox extends ICheckbox { render() { console.log("Mac Checkbox"); }}
// Abstract Factoryclass IGUIFactory { createButton() { throw new Error("createButton() must be implemented"); }
createCheckbox() { throw new Error("createCheckbox() must be implemented"); }}
// Concrete Factoriesclass WinFactory extends IGUIFactory { createButton() { return new WinButton(); }
createCheckbox() { return new WinCheckbox(); }}
class MacFactory extends IGUIFactory { createButton() { return new MacButton(); }
createCheckbox() { return new MacCheckbox(); }}
// Clientclass Application { constructor(factory) { this.button = factory.createButton(); this.checkbox = factory.createCheckbox(); }
render() { this.button.paint(); this.checkbox.render(); }}
// Usageconst factory = new WinFactory();const app = new Application(factory);app.render();Code Examples (Visual Basic)
Section titled βCode Examples (Visual Basic)β' ============================' Abstract Products' ============================Public Interface IButton Sub Paint()End Interface
Public Interface ICheckbox Sub Render()End Interface
' ============================' Concrete Products' ============================Public Class WinButton Implements IButton
Public Sub Paint() Implements IButton.Paint Console.WriteLine("Windows Button") End SubEnd Class
Public Class MacButton Implements IButton
Public Sub Paint() Implements IButton.Paint Console.WriteLine("Mac Button") End SubEnd Class
Public Class WinCheckbox Implements ICheckbox
Public Sub Render() Implements ICheckbox.Render Console.WriteLine("Windows Checkbox") End SubEnd Class
Public Class MacCheckbox Implements ICheckbox
Public Sub Render() Implements ICheckbox.Render Console.WriteLine("Mac Checkbox") End SubEnd Class
' ============================' Abstract Factory' ============================Public Interface IGUIFactory Function CreateButton() As IButton Function CreateCheckbox() As ICheckboxEnd Interface
' ============================' Concrete Factories' ============================Public Class WinFactory Implements IGUIFactory
Public Function CreateButton() As IButton Implements IGUIFactory.CreateButton Return New WinButton() End Function
Public Function CreateCheckbox() As ICheckbox Implements IGUIFactory.CreateCheckbox Return New WinCheckbox() End FunctionEnd Class
Public Class MacFactory Implements IGUIFactory
Public Function CreateButton() As IButton Implements IGUIFactory.CreateButton Return New MacButton() End Function
Public Function CreateCheckbox() As ICheckbox Implements IGUIFactory.CreateCheckbox Return New MacCheckbox() End FunctionEnd Class
' ============================' Client' ============================Public Class Application Private ReadOnly _button As IButton Private ReadOnly _checkbox As ICheckbox
Public Sub New(factory As IGUIFactory) _button = factory.CreateButton() _checkbox = factory.CreateCheckbox() End Sub
Public Sub Render() _button.Paint() _checkbox.Render() End SubEnd Class
' ============================' Usage' ============================Module Program Sub Main() Dim factory As IGUIFactory = New WinFactory() Dim app As New Application(factory) app.Render() End SubEnd ModuleCode Examples (Rust)
Section titled βCode Examples (Rust)β// Abstract Productstrait Button { fn paint(&self);}
trait Checkbox { fn render(&self);}
// Concrete Productsstruct WinButton;struct MacButton;
struct WinCheckbox;struct MacCheckbox;
impl Button for WinButton { fn paint(&self) { println!("Windows Button"); }}
impl Button for MacButton { fn paint(&self) { println!("Mac Button"); }}
impl Checkbox for WinCheckbox { fn render(&self) { println!("Windows Checkbox"); }}
impl Checkbox for MacCheckbox { fn render(&self) { println!("Mac Checkbox"); }}
// Abstract Factorytrait GuiFactory { fn create_button(&self) -> Box<dyn Button>; fn create_checkbox(&self) -> Box<dyn Checkbox>;}
// Concrete Factoriesstruct WinFactory;struct MacFactory;
impl GuiFactory for WinFactory { fn create_button(&self) -> Box<dyn Button> { Box::new(WinButton) } fn create_checkbox(&self) -> Box<dyn Checkbox> { Box::new(WinCheckbox) }}
impl GuiFactory for MacFactory { fn create_button(&self) -> Box<dyn Button> { Box::new(MacButton) } fn create_checkbox(&self) -> Box<dyn Checkbox> { Box::new(MacCheckbox) }}
// Clientstruct Application { button: Box<dyn Button>, checkbox: Box<dyn Checkbox>,}
impl Application { fn new(factory: &dyn GuiFactory) -> Self { Self { button: factory.create_button(), checkbox: factory.create_checkbox(), } }
fn render(&self) { self.button.paint(); self.checkbox.render(); }}
// Usagefn main() { let factory = WinFactory; let app = Application::new(&factory); app.render();
let factory = MacFactory; let app = Application::new(&factory); app.render();}Code Examples (PHP)
Section titled βCode Examples (PHP)β<?php
// Abstract Productsinterface IButton{ public function paint(): void;}
interface ICheckbox{ public function render(): void;}
// Concrete Productsclass WinButton implements IButton{ public function paint(): void { echo "Windows Button\n"; }}
class MacButton implements IButton{ public function paint(): void { echo "Mac Button\n"; }}
class WinCheckbox implements ICheckbox{ public function render(): void { echo "Windows Checkbox\n"; }}
class MacCheckbox implements ICheckbox{ public function render(): void { echo "Mac Checkbox\n"; }}
// Abstract Factoryinterface IGUIFactory{ public function createButton(): IButton; public function createCheckbox(): ICheckbox;}
// Concrete Factoriesclass WinFactory implements IGUIFactory{ public function createButton(): IButton { return new WinButton(); }
public function createCheckbox(): ICheckbox { return new WinCheckbox(); }}
class MacFactory implements IGUIFactory{ public function createButton(): IButton { return new MacButton(); }
public function createCheckbox(): ICheckbox { return new MacCheckbox(); }}
// Clientclass Application{ private IButton $button; private ICheckbox $checkbox;
public function __construct(IGUIFactory $factory) { $this->button = $factory->createButton(); $this->checkbox = $factory->createCheckbox(); }
public function render(): void { $this->button->paint(); $this->checkbox->render(); }}
// Usage$factory = new WinFactory();$app = new Application($factory);$app->render();Code Examples (Go)
Section titled βCode Examples (Go)βpackage main
import ( "fmt")
// Abstract Productstype Button interface { Paint()}
type Checkbox interface { Render()}
// Concrete Productstype WinButton struct{}type MacButton struct{}type WinCheckbox struct{}type MacCheckbox struct{}
func (WinButton) Paint() { fmt.Println("Windows Button")}
func (MacButton) Paint() { fmt.Println("Mac Button")}
func (WinCheckbox) Render() { fmt.Println("Windows Checkbox")}
func (MacCheckbox) Render() { fmt.Println("Mac Checkbox")}
// Abstract Factorytype GUIFactory interface { CreateButton() Button CreateCheckbox() Checkbox}
// Concrete Factoriestype WinFactory struct{}type MacFactory struct{}
func (WinFactory) CreateButton() Button { return WinButton{}}
func (WinFactory) CreateCheckbox() Checkbox { return WinCheckbox{}}
func (MacFactory) CreateButton() Button { return MacButton{}}
func (MacFactory) CreateCheckbox() Checkbox { return MacCheckbox{}}
// Clienttype Application struct { button Button checkbox Checkbox}
func NewApplication(factory GUIFactory) *Application { return &Application{ button: factory.CreateButton(), checkbox: factory.CreateCheckbox(), }}
func (app *Application) Render() { app.button.Paint() app.checkbox.Render()}
// Usagefunc main() { factory := WinFactory{} app := NewApplication(factory) app.Render()
factory = MacFactory{} app = NewApplication(factory) app.Render()}Code Examples (Ruby)
Section titled βCode Examples (Ruby)β# Abstract Productsclass Buttondef paint raise NotImplementedError, "Subclasses must implement paint"endend
class Checkboxdef render raise NotImplementedError, "Subclasses must implement render"endend
# Concrete Productsclass WinButton < Buttondef paint puts "Windows Button"endend
class MacButton < Buttondef paint puts "Mac Button"endend
class WinCheckbox < Checkboxdef render puts "Windows Checkbox"endend
class MacCheckbox < Checkboxdef render puts "Mac Checkbox"endend
# Abstract Factoryclass GUIFactorydef create_button raise NotImplementedError, "Subclasses must implement create_button"end
def create_checkbox raise NotImplementedError, "Subclasses must implement create_checkbox"endend
# Concrete Factoriesclass WinFactory < GUIFactorydef create_button WinButton.newend
def create_checkbox WinCheckbox.newendend
class MacFactory < GUIFactorydef create_button MacButton.newend
def create_checkbox MacCheckbox.newendend
# Clientclass Applicationdef initialize(factory) @button = factory.create_button @checkbox = factory.create_checkboxend
def render @button.paint @checkbox.renderendend
# Usagefactory = WinFactory.newapp = Application.new(factory)app.renderCode Examples (Perl)
Section titled βCode Examples (Perl)β#!/usr/bin/perluse strict;use warnings;
############################# Abstract Products############################package Button;sub paint { die "paint() must be implemented by subclass";}
package Checkbox;sub render { die "render() must be implemented by subclass";}
############################# Concrete Products############################package WinButton;our @ISA = ('Button');
sub new { bless {}, shift }sub paint { print "Windows Button\n"; }
package MacButton;our @ISA = ('Button');
sub new { bless {}, shift }sub paint { print "Mac Button\n"; }
package WinCheckbox;our @ISA = ('Checkbox');
sub new { bless {}, shift }sub render { print "Windows Checkbox\n"; }
package MacCheckbox;our @ISA = ('Checkbox');
sub new { bless {}, shift }sub render { print "Mac Checkbox\n"; }
############################# Abstract Factory############################package GUIFactory;
sub create_button { die "create_button() must be implemented by subclass";}
sub create_checkbox { die "create_checkbox() must be implemented by subclass";}
############################# Concrete Factories############################package WinFactory;our @ISA = ('GUIFactory');
sub new { bless {}, shift }sub create_button { WinButton->new() }sub create_checkbox { WinCheckbox->new() }
package MacFactory;our @ISA = ('GUIFactory');
sub new { bless {}, shift }sub create_button { MacButton->new() }sub create_checkbox { MacCheckbox->new() }
############################# Client############################package Application;
sub new { my ($class, $factory) = @_; my $self = bless {}, $class;
$self->{button} = $factory->create_button(); $self->{checkbox} = $factory->create_checkbox();
return $self;}
sub render { my ($self) = @_; $self->{button}->paint(); $self->{checkbox}->render();}
############################# Usage############################package main;
my $factory = WinFactory->new();my $app = Application->new($factory);$app->render();
$factory = MacFactory->new();$app = Application->new($factory);$app->render();Code Examples (TypeScript)
Section titled βCode Examples (TypeScript)β// Abstract Productsinterface IButton { paint(): void;}
interface ICheckbox { render(): void;}
// Concrete Productsclass WinButton implements IButton { paint(): void { console.log("Windows Button"); }}
class MacButton implements IButton { paint(): void { console.log("Mac Button"); }}
class WinCheckbox implements ICheckbox { render(): void { console.log("Windows Checkbox"); }}
class MacCheckbox implements ICheckbox { render(): void { console.log("Mac Checkbox"); }}
// Abstract Factoryinterface IGUIFactory { createButton(): IButton; createCheckbox(): ICheckbox;}
// Concrete Factoriesclass WinFactory implements IGUIFactory { createButton(): IButton { return new WinButton(); }
createCheckbox(): ICheckbox { return new WinCheckbox(); }}
class MacFactory implements IGUIFactory { createButton(): IButton { return new MacButton(); }
createCheckbox(): ICheckbox { return new MacCheckbox(); }}
// Clientclass Application { private button: IButton; private checkbox: ICheckbox;
constructor(factory: IGUIFactory) { this.button = factory.createButton(); this.checkbox = factory.createCheckbox(); }
render(): void { this.button.paint(); this.checkbox.render(); }}
// Usageconst factory: IGUIFactory = new WinFactory();const app = new Application(factory);app.render();