Программа курса← Объектно ориентированное программирование
1История ООП
2Объект и Класс
3Базовые концепции ООП
4Принцип проектирования GRASP
5Принцип проектирования SOLID
6Паттерны GOF

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();
    }
}
class ITransport {
public:
    virtual void Deliver() const = 0;
    virtual ~ITransport() = default;
};

class Truck : public ITransport {
public:
    void Deliver() const override {
        std::cout << "Доставка грузов по суше на грузовике." << std::endl;
    }
};

class Ship : public ITransport {
public:
    void Deliver() const override {
        std::cout << "Доставка товаров по морю на корабле." << std::endl;
    }
};

class Logistics {
public:
    virtual std::unique_ptr<ITransport> CreateTransport() const = 0;
    virtual ~Logistics() = default;

    void PlanDelivery() const { CreateTransport()->Deliver(); }
};

class RoadLogistics : public Logistics {
public:
    std::unique_ptr<ITransport> CreateTransport() const override {
        return std::make_unique<Truck>();
    }
};

class SeaLogistics : public Logistics {
public:
    std::unique_ptr<ITransport> CreateTransport() const override {
        return std::make_unique<Ship>();
    }
};
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 – один из самых распространённых порождающих паттернов. Он помогает разделить логику создания объектов и их использование, делая систему более гибкой и устойчивой к изменениям.