Abstract Factory (Абстрактная фабрика)

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

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

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

PlantUML-диаграмма

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

public interface IButton
{
    void Paint();
}

public interface ICheckbox
{
    void Paint();
}

// Конкретные продукты
public class WinButton : IButton
{
    public void Paint() => Console.WriteLine("Рисуем кнопку в стиле Windows.");
}

public class WinCheckbox : ICheckbox
{
    public void Paint() => Console.WriteLine("Рисуем чекбокс в стиле Windows.");
}

public class MacButton : IButton
{
    public void Paint() => Console.WriteLine("Рисуем кнопку в стиле macOS.");
}

public class MacCheckbox : ICheckbox
{
    public void Paint() => Console.WriteLine("Рисуем чекбокс в стиле macOS.");
}

// Абстрактная фабрика
public interface IGUIFactory
{
    IButton CreateButton();
    ICheckbox CreateCheckbox();
}

// Конкретные фабрики
public 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();
}

// Клиент
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.Paint();
    }
}

class Program
{
    static void Main()
    {
        IGUIFactory factory;

        // Пример: выбираем фабрику в зависимости от ОС
        string os = "Windows";
        factory = os == "Windows" ? new WinFactory() : new MacFactory();

        var app = new Application(factory);
        app.Render();
    }
}
type Button interface{ Paint() }

type Checkbox interface{ Paint() }

type WinButton struct{}

func (WinButton) Paint() { fmt.Println("Рисуем кнопку в стиле Windows.") }

type WinCheckbox struct{}

func (WinCheckbox) Paint() { fmt.Println("Рисуем чекбокс в стиле Windows.") }

type MacButton struct{}

func (MacButton) Paint() { fmt.Println("Рисуем кнопку в стиле macOS.") }

type MacCheckbox struct{}

func (MacCheckbox) Paint() { fmt.Println("Рисуем чекбокс в стиле macOS.") }

// Абстрактная фабрика
type GUIFactory interface {
	CreateButton() Button
	CreateCheckbox() Checkbox
}

type WinFactory struct{}

func (WinFactory) CreateButton() Button     { return WinButton{} }
func (WinFactory) CreateCheckbox() Checkbox { return WinCheckbox{} }

type MacFactory struct{}

func (MacFactory) CreateButton() Button     { return MacButton{} }
func (MacFactory) CreateCheckbox() Checkbox { return MacCheckbox{} }

type Application struct {
	button   Button
	checkbox Checkbox
}

func NewApplication(f GUIFactory) *Application {
	return &Application{button: f.CreateButton(), checkbox: f.CreateCheckbox()}
}

func (a *Application) Render() {
	a.button.Paint()
	a.checkbox.Paint()
}

func main() {
	var factory GUIFactory = WinFactory{}
	if os := "Windows"; os != "Windows" {
		factory = MacFactory{}
	}

	NewApplication(factory).Render()
}
from abc import ABC, abstractmethod


class Button(ABC):
    @abstractmethod
    def paint(self) -> None: ...


class Checkbox(ABC):
    @abstractmethod
    def paint(self) -> None: ...


class WinButton(Button):
    def paint(self) -> None:
        print("Рисуем кнопку в стиле Windows.")


class WinCheckbox(Checkbox):
    def paint(self) -> None:
        print("Рисуем чекбокс в стиле Windows.")


class MacButton(Button):
    def paint(self) -> None:
        print("Рисуем кнопку в стиле macOS.")


class MacCheckbox(Checkbox):
    def paint(self) -> None:
        print("Рисуем чекбокс в стиле macOS.")


class GUIFactory(ABC):
    @abstractmethod
    def create_button(self) -> Button: ...

    @abstractmethod
    def create_checkbox(self) -> Checkbox: ...


class WinFactory(GUIFactory):
    def create_button(self) -> Button:
        return WinButton()

    def create_checkbox(self) -> Checkbox:
        return WinCheckbox()


class MacFactory(GUIFactory):
    def create_button(self) -> Button:
        return MacButton()

    def create_checkbox(self) -> Checkbox:
        return MacCheckbox()


class Application:
    def __init__(self, factory: GUIFactory) -> None:
        self.button = factory.create_button()
        self.checkbox = factory.create_checkbox()

    def render(self) -> None:
        self.button.paint()
        self.checkbox.paint()


os_name = "Windows"
factory = WinFactory() if os_name == "Windows" else MacFactory()
Application(factory).render()
interface Button {
    paint(): void;
}

interface Checkbox {
    paint(): void;
}

class WinButton implements Button {
    paint(): void {
        console.log("Рисуем кнопку в стиле Windows.");
    }
}

class WinCheckbox implements Checkbox {
    paint(): void {
        console.log("Рисуем чекбокс в стиле Windows.");
    }
}

class MacButton implements Button {
    paint(): void {
        console.log("Рисуем кнопку в стиле macOS.");
    }
}

class MacCheckbox implements Checkbox {
    paint(): void {
        console.log("Рисуем чекбокс в стиле macOS.");
    }
}

interface GUIFactory {
    createButton(): Button;
    createCheckbox(): Checkbox;
}

class WinFactory implements GUIFactory {
    createButton(): Button {
        return new WinButton();
    }

    createCheckbox(): Checkbox {
        return new WinCheckbox();
    }
}

class MacFactory implements GUIFactory {
    createButton(): Button {
        return new MacButton();
    }

    createCheckbox(): Checkbox {
        return new MacCheckbox();
    }
}

class Application {
    private readonly button: Button;
    private readonly checkbox: Checkbox;

    constructor(factory: GUIFactory) {
        this.button = factory.createButton();
        this.checkbox = factory.createCheckbox();
    }

    render(): void {
        this.button.paint();
        this.checkbox.paint();
    }
}

const os = "Windows";
const factory: GUIFactory = os === "Windows" ? new WinFactory() : new MacFactory();
new Application(factory).render();
interface Button {
    void paint();
}

interface Checkbox {
    void paint();
}

class WinButton implements Button {
    public void paint() {
        System.out.println("Рисуем кнопку в стиле Windows.");
    }
}

class WinCheckbox implements Checkbox {
    public void paint() {
        System.out.println("Рисуем чекбокс в стиле Windows.");
    }
}

class MacButton implements Button {
    public void paint() {
        System.out.println("Рисуем кнопку в стиле macOS.");
    }
}

class MacCheckbox implements Checkbox {
    public void paint() {
        System.out.println("Рисуем чекбокс в стиле macOS.");
    }
}

interface GUIFactory {
    Button createButton();
    Checkbox createCheckbox();
}

class WinFactory implements GUIFactory {
    public Button createButton() {
        return new WinButton();
    }

    public Checkbox createCheckbox() {
        return new WinCheckbox();
    }
}

class MacFactory implements GUIFactory {
    public Button createButton() {
        return new MacButton();
    }

    public Checkbox createCheckbox() {
        return new MacCheckbox();
    }
}

class Application {
    private final Button button;
    private final Checkbox checkbox;

    Application(GUIFactory factory) {
        this.button = factory.createButton();
        this.checkbox = factory.createCheckbox();
    }

    void render() {
        button.paint();
        checkbox.paint();
    }
}

public class Program {
    public static void main(String[] args) {
        String os = "Windows";
        GUIFactory factory = os.equals("Windows") ? new WinFactory() : new MacFactory();

        new Application(factory).render();
    }
}
interface Button {
    fun paint()
}

interface Checkbox {
    fun paint()
}

class WinButton : Button {
    override fun paint() = println("Рисуем кнопку в стиле Windows.")
}

class WinCheckbox : Checkbox {
    override fun paint() = println("Рисуем чекбокс в стиле Windows.")
}

class MacButton : Button {
    override fun paint() = println("Рисуем кнопку в стиле macOS.")
}

class MacCheckbox : Checkbox {
    override fun paint() = println("Рисуем чекбокс в стиле macOS.")
}

interface GUIFactory {
    fun createButton(): Button
    fun createCheckbox(): Checkbox
}

class WinFactory : GUIFactory {
    override fun createButton(): Button = WinButton()
    override fun createCheckbox(): Checkbox = WinCheckbox()
}

class MacFactory : GUIFactory {
    override fun createButton(): Button = MacButton()
    override fun createCheckbox(): Checkbox = MacCheckbox()
}

class Application(factory: GUIFactory) {
    private val button = factory.createButton()
    private val checkbox = factory.createCheckbox()

    fun render() {
        button.paint()
        checkbox.paint()
    }
}

fun main() {
    val os = "Windows"
    val factory: GUIFactory = if (os == "Windows") WinFactory() else MacFactory()

    Application(factory).render()
}

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

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

Заключение

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