Factory Method (Фабричный метод)

Паттерн Factory Method определяет интерфейс для создания объектов, но позволяет подклассам решать, какой класс инстанцировать. Он делегирует создание объектов дочерним классам, обеспечивая гибкость и расширяемость системы.

Когда применять Factory Method

  • Когда заранее неизвестно, какие конкретные объекты нужно создавать.
  • Чтобы избавиться от жёстких зависимостей между классами.
  • Чтобы добавить новые типы продуктов без изменения существующего кода.

PlantUML-диаграмма

UML диаграмма Factory Method

public interface ITransport
{
    void Deliver();
}

public class Truck : ITransport
{
    public void Deliver()
    {
        Console.WriteLine("Доставка грузов по суше на грузовике.");
    }
}

public class Ship : ITransport
{
    public void Deliver()
    {
        Console.WriteLine("Доставка товаров по морю на корабле.");
    }
}

public abstract class Logistics
{
    public abstract ITransport CreateTransport();

    public void PlanDelivery()
    {
        var transport = CreateTransport();
        transport.Deliver();
    }
}

public class RoadLogistics : Logistics
{
    public override ITransport CreateTransport() => new Truck();
}

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

// Использование
class Program
{
    static void Main()
    {
        Logistics logistics = new RoadLogistics();
        logistics.PlanDelivery();

        logistics = new SeaLogistics();
        logistics.PlanDelivery();
    }
}
type Transport interface {
	Deliver()
}

type Truck struct{}

func (Truck) Deliver() { fmt.Println("Доставка грузов по суше на грузовике.") }

type Ship struct{}

func (Ship) Deliver() { fmt.Println("Доставка товаров по морю на корабле.") }

// Абстрактных классов в Go нет: общую часть выносим в функцию,
// а «фабричный метод» передаём обычной функцией-конструктором.
type Logistics func() Transport

func (create Logistics) PlanDelivery() {
	create().Deliver()
}

func RoadLogistics() Transport { return Truck{} }

func SeaLogistics() Transport { return Ship{} }

func main() {
	var logistics Logistics = RoadLogistics
	logistics.PlanDelivery()

	logistics = SeaLogistics
	logistics.PlanDelivery()
}
from abc import ABC, abstractmethod


class Transport(ABC):
    @abstractmethod
    def deliver(self) -> None: ...


class Truck(Transport):
    def deliver(self) -> None:
        print("Доставка грузов по суше на грузовике.")


class Ship(Transport):
    def deliver(self) -> None:
        print("Доставка товаров по морю на корабле.")


class Logistics(ABC):
    @abstractmethod
    def create_transport(self) -> Transport: ...

    def plan_delivery(self) -> None:
        self.create_transport().deliver()


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


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


logistics: Logistics = RoadLogistics()
logistics.plan_delivery()

logistics = SeaLogistics()
logistics.plan_delivery()
interface Transport {
    deliver(): void;
}

class Truck implements Transport {
    deliver(): void {
        console.log("Доставка грузов по суше на грузовике.");
    }
}

class Ship implements Transport {
    deliver(): void {
        console.log("Доставка товаров по морю на корабле.");
    }
}

abstract class Logistics {
    abstract createTransport(): Transport;

    planDelivery(): void {
        this.createTransport().deliver();
    }
}

class RoadLogistics extends Logistics {
    createTransport(): Transport {
        return new Truck();
    }
}

class SeaLogistics extends Logistics {
    createTransport(): Transport {
        return new Ship();
    }
}

let logistics: Logistics = new RoadLogistics();
logistics.planDelivery();

logistics = new SeaLogistics();
logistics.planDelivery();
interface Transport {
    void deliver();
}

class Truck implements Transport {
    public void deliver() {
        System.out.println("Доставка грузов по суше на грузовике.");
    }
}

class Ship implements Transport {
    public void deliver() {
        System.out.println("Доставка товаров по морю на корабле.");
    }
}

abstract class Logistics {
    abstract Transport createTransport();

    void planDelivery() {
        createTransport().deliver();
    }
}

class RoadLogistics extends Logistics {
    Transport createTransport() {
        return new Truck();
    }
}

class SeaLogistics extends Logistics {
    Transport createTransport() {
        return new Ship();
    }
}

public class Program {
    public static void main(String[] args) {
        Logistics logistics = new RoadLogistics();
        logistics.planDelivery();

        logistics = new SeaLogistics();
        logistics.planDelivery();
    }
}
interface Transport {
    fun deliver()
}

class Truck : Transport {
    override fun deliver() = println("Доставка грузов по суше на грузовике.")
}

class Ship : Transport {
    override fun deliver() = println("Доставка товаров по морю на корабле.")
}

abstract class Logistics {
    abstract fun createTransport(): Transport

    fun planDelivery() = createTransport().deliver()
}

class RoadLogistics : Logistics() {
    override fun createTransport(): Transport = Truck()
}

class SeaLogistics : Logistics() {
    override fun createTransport(): Transport = Ship()
}

fun main() {
    var logistics: Logistics = RoadLogistics()
    logistics.planDelivery()

    logistics = SeaLogistics()
    logistics.planDelivery()
}

Плюсы и минусы

Плюсы Минусы
Избавляет от жёстких зависимостей между создателем и продуктами Увеличивает количество классов в программе
Упрощает добавление новых продуктов Требует создания иерархии классов для каждого нового продукта
Следует принципу открытости/закрытости (OCP) Иногда кажется избыточным для простых задач

Заключение

Factory Method — один из самых распространённых порождающих паттернов. Он помогает разделить логику создания объектов и их использование, делая систему более гибкой и устойчивой к изменениям.