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

Для чего нужен паттерн Фабрика Factory?

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

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

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

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

Паттерн Factory (Фабрика)

Назначение

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

Проблема, которую решает Factory

❌ Без паттерна:

// Клиентский код зависит от конкретных реализаций
if (databaseType.equals("mysql")) {
    connection = new MySQLConnection();
} else if (databaseType.equals("postgresql")) {
    connection = new PostgreSQLConnection();
} else if (databaseType.equals("oracle")) {
    connection = new OracleConnection();
}

connection.connect();

Проблемы:

  • Код зависит от конкретных классов
  • Сложно добавлять новые типы
  • Логика создания размазана по коду
  • Нарушается принцип Open/Closed

Решение с Factory

✅ С паттерном:

// Интерфейс для всех типов соединений
public interface DatabaseConnection {
    void connect();
    void disconnect();
    void executeQuery(String sql);
}

// Конкретные реализации
public class MySQLConnection implements DatabaseConnection {
    @Override
    public void connect() {
        System.out.println("Connecting to MySQL...");
    }
    
    @Override
    public void disconnect() {
        System.out.println("Disconnecting from MySQL...");
    }
    
    @Override
    public void executeQuery(String sql) {
        System.out.println("Executing MySQL query: " + sql);
    }
}

public class PostgreSQLConnection implements DatabaseConnection {
    @Override
    public void connect() {
        System.out.println("Connecting to PostgreSQL...");
    }
    
    @Override
    public void disconnect() {
        System.out.println("Disconnecting from PostgreSQL...");
    }
    
    @Override
    public void executeQuery(String sql) {
        System.out.println("Executing PostgreSQL query: " + sql);
    }
}

// Фабрика
public class DatabaseConnectionFactory {
    public static DatabaseConnection createConnection(String databaseType) {
        return switch (databaseType.toLowerCase()) {
            case "mysql" -> new MySQLConnection();
            case "postgresql" -> new PostgreSQLConnection();
            case "oracle" -> new OracleConnection();
            default -> throw new IllegalArgumentException(
                "Unknown database type: " + databaseType
            );
        };
    }
}

// Клиентский код
DatabaseConnection connection = DatabaseConnectionFactory.createConnection("mysql");
connection.connect();
connection.executeQuery("SELECT * FROM users");
connection.disconnect();

Типы Factory паттернов

1. Simple Factory (Простая фабрика)

Статический метод в утилитарном классе:

public class LoggerFactory {
    public static Logger createLogger(LogLevel level) {
        return switch (level) {
            case DEBUG -> new DebugLogger();
            case INFO -> new InfoLogger();
            case ERROR -> new ErrorLogger();
        };
    }
}

2. Factory Method (Метод-фабрика)

Определяется в интерфейсе, реализуется в подклассах:

// Абстрактный класс с методом-фабрикой
public abstract class Document {
    public abstract Application createApplication();
    
    public void open() {
        Application app = createApplication();
        app.init();
    }
}

// Конкретные реализации
public class PDFDocument extends Document {
    @Override
    public Application createApplication() {
        return new PDFReader();
    }
}

public class WordDocument extends Document {
    @Override
    public Application createApplication() {
        return new WordProcessor();
    }
}

// Использование
Document pdf = new PDFDocument();
pdf.open(); // Откроет PDF Reader

Document word = new WordDocument();
word.open(); // Откроет Word Processor

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

Создаёт семейства связанных объектов:

// Интерфейсы для компонентов UI
public interface Button {
    void render();
}

public interface Checkbox {
    void render();
}

// Фабрика для создания компонентов
public interface UIFactory {
    Button createButton();
    Checkbox createCheckbox();
}

// Реализации для Windows
public class WindowsButton implements Button {
    @Override
    public void render() {
        System.out.println("Rendering Windows button");
    }
}

public class WindowsCheckbox implements Checkbox {
    @Override
    public void render() {
        System.out.println("Rendering Windows checkbox");
    }
}

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

// Реализации для macOS
public class MacButton implements Button {
    @Override
    public void render() {
        System.out.println("Rendering macOS button");
    }
}

public class MacCheckbox implements Checkbox {
    @Override
    public void render() {
        System.out.println("Rendering macOS checkbox");
    }
}

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

// Использование
UIFactory factory;
if (System.getProperty("os.name").contains("Windows")) {
    factory = new WindowsUIFactory();
} else {
    factory = new MacUIFactory();
}

Button button = factory.createButton();
Checkbox checkbox = factory.createCheckbox();

button.render();
checkbox.render();

Преимущества Factory

  1. Инкапсуляция — логика создания скрыта
  2. Слабая связанность — клиент зависит от интерфейса, не от реализаций
  3. Простота расширения — добавляем новый класс без изменения существующего кода (Open/Closed Principle)
  4. Централизованное управление — изменения в логике создания в одном месте
  5. Контроль — фабрика может кэшировать объекты, переиспользовать их

Примеры из Java API

// java.util.Calendar
Calendar calendar = Calendar.getInstance(); // Factory method

// java.nio.file.Files
Path path = Files.getPath("/etc/config");

// java.time
LocalDate date = LocalDate.now();
LocalDate date2 = LocalDate.of(2024, 3, 22);

// javax.xml.parsers
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();

Factory vs Constructor

АспектConstructorFactory
СложностьПростойМожет быть сложным
ЛогикаПрямаяМожет скрывать логику
КэшированиеНетДа
ПолиморфизмНетДа
ПроизводительностьБыстроМожет быть медленнее

Рекомендации

  • Используй Factory когда нужна полиморфная создание объектов
  • Используй Constructor когда логика создания простая
  • Используй Abstract Factory для семейств объектов
  • Комбинируй с Builder для сложных объектов с параметрами

Factory паттерн — фундаментальный паттерн для построения слабосвязанных и расширяемых систем.