Что такое паттерн Фабричный метод?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
📖 Общее определение
Паттерн Фабричный метод (Factory Method) — это порождающий паттерн проектирования, который определяет общий интерфейс для создания объектов в суперклассе, позволяя подклассам изменять тип создаваемых объектов. Он инкапсулирует логику создания объектов, делегируя её подклассам, что способствует соблюдению принципа открытости/закрытости (Open/Closed Principle).
🎯 Основная идея и проблема
Главная проблема, которую решает Factory Method — необходимость создавать объекты, не привязывая код к конкретным классам. Вместо прямого вызова конструктора (SomeClass()), мы используем специальный фабричный метод, который возвращает нужный экземпляр.
Классическая аналогия из iOS: Представьте, что ваш ViewController должен отобразить разные типы ячеек таблицы (UITableViewCell) в зависимости от типа контента. Прямое создание ячеек в методе cellForRowAt приводит к нагромождению условной логики и нарушению SRP. Фабричный метод выносит эту логику в отдельный компонент.
🔧 Ключевые компоненты паттерна
- Продукт (Product) — общий интерфейс или базовый класс для объектов, которые будет создавать фабрика.
- Конкретные продукты (Concrete Products) — реализации интерфейса
Product. - Создатель (Creator) — базовый класс (или протокол), объявляющий фабричный метод, возвращающий объект типа
Product. Он может содержать и бизнес-логику, связанную с продуктами. - Конкретные создатели (Concrete Creators) — переопределяют фабричный метод, чтобы возвращать конкретный экземпляр
ConcreteProduct.
📱 Пример на Swift (UIKit)
Рассмотрим реальный кейс: создание алертов в разных стилях.
1. Определяем "Продукты" — типы алертов
// Базовый протокол для продукта
protocol AlertView {
func show()
}
// Конкретные продукты
class SuccessAlert: AlertView {
let message: String
init(message: String) { self.message = message }
func show() { print("✅ Success: \(message)") }
}
class ErrorAlert: AlertView {
let message: String
init(message: String) { self.message = message }
func show() { print("❌ Error: \(message)") }
}
class LoadingAlert: AlertView {
let message: String
init(message: String) { self.message = message }
func show() { print("⏳ Loading: \(message)") }
}
2. Создаем "Создателя" с фабричным методом
// Базовый создатель (может быть классом или протоколом)
protocol AlertFactory {
// ФАБРИЧНЫЙ МЕТОД (может иметь параметры)
func createAlert(message: String) -> AlertView
// Дополнительная бизнес-логика, использующая продукт
func presentAlert(message: String)
}
// Расширение с реализацией логики по умолчанию
extension AlertFactory {
func presentAlert(message: String) {
let alert = createAlert(message: message)
alert.show()
// Здесь может быть вызов UIViewController.present() и т.д.
}
}
3. Реализуем "Конкретных создателей"
// Конкретные фабрики
class SuccessAlertFactory: AlertFactory {
// Каждая фабрика определяет СВОЮ реализацию фабричного метода
func createAlert(message: String) -> AlertView {
return SuccessAlert(message: message)
}
}
class ErrorAlertFactory: AlertFactory {
func createAlert(message: String) -> AlertView {
return ErrorAlert(message: message)
}
}
class LoadingAlertFactory: AlertFactory {
func createAlert(message: String) -> AlertView {
return LoadingAlert(message: message)
}
}
4. Использование в клиентском коде
class ViewController {
var alertFactory: AlertFactory!
func userDidLogin() {
alertFactory = SuccessAlertFactory()
alertFactory.presentAlert(message: "Login successful!")
// Выведет: ✅ Success: Login successful!
}
func dataLoadingFailed() {
alertFactory = ErrorAlertFactory()
alertFactory.presentAlert(message: "Network error")
// Выведет: ❌ Error: Network error
}
}
✅ Преимущества использования
- Избегание жесткой привязки: Клиентский код работает с интерфейсом
AlertView, а не с конкретными классами. - Принцип единственной ответственности (SRP): Код создания объекта переносится в одно место, упрощая поддержку.
- Принцип открытости/закрытости (OCP): Вы можете добавлять новые типы алертов (новые
ConcreteProduct) и новые фабрики, не изменяя существующий клиентский код. - Упрощение тестирования: Фабрику легко подменить мок-объектом в unit-тестах.
- Читаемость: Инициализация сложных объектов с множеством параметров инкапсулирована.
⚠️ Когда применять (и когда нет)
Используйте Factory Method, когда:
- Заранее неизвестно, объекты каких конкретных типов понадобятся.
- Код должен быть расширяем для новых типов продуктов.
- Есть необходимость вынести процесс создания объектов для повторного использования или централизованного управления (например, конфигурация).
Рассмотрите другие варианты (Abstract Factory, Builder), когда:
- Процесс создания объекта очень сложный и требует много шагов.
- Необходимо создавать целые семейства связанных объектов.
🆚 Отличие от Абстрактной фабрики (Abstract Factory)
Частая путаница! Фабричный метод — это один метод, создающий один тип продукта. Абстрактная фабрика — это набор фабричных методов, создающих семейство связанных продуктов. Если упростить: Factory Method использует наследование, Abstract Factory — композицию.
Factory Method в iOS SDK можно увидеть в таких примерах, как UICollectionViewCell с методом register(_:forCellWithReuseIdentifier:) и последующим созданием через dequeueReusableCell(withReuseIdentifier:for:). Система выступает в роли Creator, а ваш зарегистрированный класс клетки — Concrete Product.
Таким образом, паттерн Фабричный метод — это мощный и элегантный инструмент для повышения гибкости, тестируемости и чистоты кода, который активно применяется в iOS-разработке для управления жизненным циклом объектов.