← Назад к вопросам

Когда используют Абстрактную фабрику?

2.0 Middle🔥 191 комментариев
#SOLID и паттерны проектирования

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Abstract Factory: Когда и почему использовать

Определение

Abstract Factory (Абстрактная фабрика) — это паттерн проектирования, который позволяет создавать семейства связанных объектов без указания их конкретных классов. Это паттерн уровня объектов, который работает с группами объектов.

Основной принцип

Вместо того чтобы создавать объекты напрямую через new, вы определяете интерфейс фабрики, который выдаёт объекты. Это позволяет менять всё семейство объектов, не изменяя код, который их использует.

Когда используется Abstract Factory

1. Множество семейств связанных объектов

Если система должна работать с несколькими семействами связанных объектов (например, разные UI-темы для разных операционных систем):

// Семейство объектов для Windows
class WindowsButton implements Button { /* ... */ }
class WindowsCheckbox implements Checkbox { /* ... */ }

// Семейство объектов для macOS
class MacButton implements Button { /* ... */ }
class MacCheckbox implements Checkbox { /* ... */ }

// Семейство объектов для Linux
class LinuxButton implements Button { /* ... */ }
class LinuxCheckbox implements Checkbox { /* ... */ }

2. Условие выбора семейства известно во время выполнения

Вы не можете определить заранее, какое семейство нужно использовать:

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

public class WindowsFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new WindowsButton();
    }
    
    @Override
    public Checkbox createCheckbox() {
        return new WindowsCheckbox();
    }
}

public class MacFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new MacButton();
    }
    
    @Override
    public Checkbox createCheckbox() {
        return new MacCheckbox();
    }
}

3. Нужна консистентность между объектами одного семейства

Паттерн гарантирует, что вы не будете использовать WindowsButton с MacCheckbox:

public class Application {
    private GUIFactory factory;
    private Button button;
    private Checkbox checkbox;
    
    public Application(GUIFactory factory) {
        this.factory = factory;
    }
    
    public void createUI() {
        // Оба объекта из одного семейства
        button = factory.createButton();
        checkbox = factory.createCheckbox();
    }
}

Реальный пример: Различные базы данных

// Интерфейсы продуктов
public interface Connection {
    void executeQuery(String sql);
}

public interface PreparedStatement {
    void setString(int index, String value);
    ResultSet execute();
}

// Абстрактная фабрика
public interface DatabaseFactory {
    Connection createConnection(String url);
    PreparedStatement createPreparedStatement(String sql);
}

// Реализация для PostgreSQL
public class PostgresFactory implements DatabaseFactory {
    @Override
    public Connection createConnection(String url) {
        return new PostgresConnection(url);
    }
    
    @Override
    public PreparedStatement createPreparedStatement(String sql) {
        return new PostgresPreparedStatement(sql);
    }
}

// Реализация для MySQL
public class MySQLFactory implements DatabaseFactory {
    @Override
    public Connection createConnection(String url) {
        return new MySQLConnection(url);
    }
    
    @Override
    public PreparedStatement createPreparedStatement(String sql) {
        return new MySQLPreparedStatement(sql);
    }
}

// Использование
public class DataAccessLayer {
    private DatabaseFactory factory;
    
    public DataAccessLayer(DatabaseFactory factory) {
        this.factory = factory;
    }
    
    public void executeQuery(String sql) {
        Connection conn = factory.createConnection("jdbc:postgres://localhost");
        PreparedStatement stmt = factory.createPreparedStatement(sql);
        stmt.execute();
    }
}

Практический пример: Различные платежные системы

// Интерфейсы
public interface PaymentGateway {
    void processPayment(double amount);
}

public interface NotificationService {
    void sendConfirmation(String message);
}

// Абстрактная фабрика
public interface PaymentFactory {
    PaymentGateway createPaymentGateway();
    NotificationService createNotificationService();
}

// Реализация для Stripe
public class StripeFactory implements PaymentFactory {
    @Override
    public PaymentGateway createPaymentGateway() {
        return new StripeGateway();
    }
    
    @Override
    public NotificationService createNotificationService() {
        return new StripeNotificationService();
    }
}

// Реализация для Yandex.Kassa
public class YandexFactory implements PaymentFactory {
    @Override
    public PaymentGateway createPaymentGateway() {
        return new YandexGateway();
    }
    
    @Override
    public NotificationService createNotificationService() {
        return new YandexNotificationService();
    }
}

// Использование
public class CheckoutService {
    private PaymentFactory factory;
    
    public CheckoutService(PaymentFactory factory) {
        this.factory = factory;
    }
    
    public void processOrder(Order order) {
        PaymentGateway gateway = factory.createPaymentGateway();
        NotificationService notifier = factory.createNotificationService();
        
        gateway.processPayment(order.getAmount());
        notifier.sendConfirmation("Payment processed for order " + order.getId());
    }
}

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

Плюсы:

  • ✅ Изолирует создание объектов
  • ✅ Упрощает добавление новых семейств
  • ✅ Гарантирует консистентность между объектами
  • ✅ Облегчает тестирование (можно создать MockFactory)

Минусы:

  • ❌ Усложняет код при небольшом количестве семейств
  • ❌ Требует создания многих интерфейсов и классов
  • ❌ Может быть излишним для простых задач

Отличие от Factory Method

  • Factory Method: создаёт один тип объектов
  • Abstract Factory: создаёт семейства связанных объектов

Abstract Factory часто использует Factory Method для создания объектов.

Когда НЕ использовать

  1. Если у вас одно семейство объектов
  2. Если семейства не меняются
  3. Если нет требования к независимости от конкретных классов
  4. Когда Simple Factory будет достаточно

Заключение

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