<aside> 📚 📁 Category: Creational Pattern

</aside>

Overview

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.

<aside> â„šī¸ When to use: When you don't know beforehand the exact types and dependencies of the objects your code should work with, or when you want to provide users of your library or framework with a way to extend its internal components.

</aside>

Implementation in C#

// Product interface
public interface ITransport
{
    void Deliver();
}

// Concrete Products
public class Truck : ITransport
{
    public void Deliver()
    {
        Console.WriteLine("Deliver by land in a truck");
    }
}

public class Ship : ITransport
{
    public void Deliver()
    {
        Console.WriteLine("Deliver by sea in a ship");
    }
}

public class Plane : ITransport
{
    public void Deliver()
    {
        Console.WriteLine("Deliver by air in a plane");
    }
}
// Creator abstract class
public abstract class Logistics
{
    // Factory Method
    public abstract ITransport CreateTransport();
    
    public void PlanDelivery()
    {
        ITransport transport = CreateTransport();
        transport.Deliver();
    }
}

// Concrete Creators
public class RoadLogistics : Logistics
{
    public override ITransport CreateTransport()
    {
        return new Truck();
    }
}

public class SeaLogistics : Logistics
{
    public override ITransport CreateTransport()
    {
        return new Ship();
    }
}

public class AirLogistics : Logistics
{
    public override ITransport CreateTransport()
    {
        return new Plane();
    }
}
Logistics logistics;

// Client decides which logistics to use
string type = "air";

if (type == "road")
    logistics = new RoadLogistics();
else if (type == "sea")
    logistics = new SeaLogistics();
else
    logistics = new AirLogistics();

logistics.PlanDelivery(); // Output: Deliver by air in a plane

Implementation in Python

from abc import ABC, abstractmethod

# Product
class Transport(ABC):
    @abstractmethod
    def deliver(self):
        pass

class Truck(Transport):
    def deliver(self):
        return "Deliver by land in a truck"

class Ship(Transport):
    def deliver(self):
        return "Deliver by sea in a ship"

# Creator
class Logistics(ABC):
    @abstractmethod
    def create_transport(self) -> Transport:
        pass
    
    def plan_delivery(self):
        transport = self.create_transport()
        return transport.deliver()

class RoadLogistics(Logistics):
    def create_transport(self) -> Transport:
        return Truck()

class SeaLogistics(Logistics):
    def create_transport(self) -> Transport:
        return Ship()

# Usage
logistics = RoadLogistics()
print(logistics.plan_delivery())

Real-World Example: Document Creator

public interface IDocument
{
    void Open();
    void Save();
}

public class PdfDocument : IDocument
{
    public void Open() => Console.WriteLine("Opening PDF document");
    public void Save() => Console.WriteLine("Saving as PDF");
}

public class WordDocument : IDocument
{
    public void Open() => Console.WriteLine("Opening Word document");
    public void Save() => Console.WriteLine("Saving as DOCX");
}

public abstract class DocumentCreator
{
    public abstract IDocument CreateDocument();
    
    public void NewDocument()
    {
        var doc = CreateDocument();
        doc.Open();
    }
}

public class PdfCreator : DocumentCreator
{
    public override IDocument CreateDocument() => new PdfDocument();
}

public class WordCreator : DocumentCreator
{
    public override IDocument CreateDocument() => new WordDocument();
}

Pros and Cons