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

Что такое паттерн Фабричный метод?

1.0 Junior🔥 181 комментариев
#Архитектура и паттерны

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

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

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

Что такое паттерн Фабричный метод?

Фабричный метод (Factory Method) — это порождающий паттерн проектирования, который позволяет создавать объекты без привязки кода к конкретным классам. Вместо прямого создания объекта через конструктор (new), ты используешь специальный метод, который решает какой класс инстанцировать. Это обеспечивает гибкость и упрощает добавление новых типов объектов в будущем.

Проблема без паттерна

// Плохо — жёсткая привязка к конкретным классам
class OrderProcessor {
    fun processPayment(type: String): PaymentService {
        return when (type) {
            "stripe" -> StripePaymentService()
            "paypal" -> PayPalPaymentService()
            "apple_pay" -> ApplePayService()
            else -> throw IllegalArgumentException("Unknown type")
        }
    }
}

Проблемы:

  • Код разбросан по приложению
  • Сложно добавить новый способ оплаты
  • Нарушается принцип Open/Closed (открыта для модификации, закрыта для расширения)
  • Тяжело тестировать

Решение с Factory Method

// 1. Интерфейс для создаваемых объектов
interface PaymentService {
    fun pay(amount: Double)
}

// 2. Конкретные реализации
class StripePaymentService : PaymentService {
    override fun pay(amount: Double) {
        println("Paying $amount via Stripe")
    }
}

class PayPalPaymentService : PaymentService {
    override fun pay(amount: Double) {
        println("Paying $amount via PayPal")
    }
}

class ApplePayService : PaymentService {
    override fun pay(amount: Double) {
        println("Paying $amount via Apple Pay")
    }
}

// 3. Абстрактный фабрикант
abstract class PaymentFactory {
    abstract fun createPaymentService(): PaymentService
}

// 4. Конкретные фабрики
class StripePaymentFactory : PaymentFactory() {
    override fun createPaymentService() = StripePaymentService()
}

class PayPalPaymentFactory : PaymentFactory() {
    override fun createPaymentService() = PayPalPaymentService()
}

class ApplePayFactory : PaymentFactory() {
    override fun createPaymentService() = ApplePayService()
}

// 5. Использование
class OrderProcessor {
    fun processPayment(factory: PaymentFactory, amount: Double) {
        val paymentService = factory.createPaymentService()
        paymentService.pay(amount)
    }
}

Более элегантное решение с функциями

В Kotlin можно использовать более простой подход:

object PaymentServiceFactory {
    private val factories = mutableMapOf<String, () -> PaymentService>()
    
    init {
        factories["stripe"] = { StripePaymentService() }
        factories["paypal"] = { PayPalPaymentService() }
        factories["apple_pay"] = { ApplePayService() }
    }
    
    fun create(type: String): PaymentService {
        return factories[type]?.invoke()
            ?: throw IllegalArgumentException("Unknown payment type: $type")
    }
    
    fun register(type: String, factory: () -> PaymentService) {
        factories[type] = factory
    }
}

// Использование
val service = PaymentServiceFactory.create("stripe")
service.pay(99.99)

// Добавление нового способа оплаты в runtime
PaymentServiceFactory.register("cryptocurrency") { CryptoPaymentService() }

Пример в Android: Dialog Factory

object DialogFactory {
    fun createDialog(
        context: Context,
        type: DialogType
    ): AlertDialog {
        val builder = AlertDialog.Builder(context)
        
        return when (type) {
            DialogType.CONFIRMATION -> {
                builder
                    .setTitle("Confirm Action")
                    .setPositiveButton("OK") { _, _ -> }
                    .setNegativeButton("Cancel") { _, _ -> }
                    .create()
            }
            DialogType.LOADING -> {
                builder
                    .setTitle("Loading...")
                    .setMessage("Please wait")
                    .setCancelable(false)
                    .create()
            }
            DialogType.ERROR -> {
                builder
                    .setTitle("Error")
                    .setIcon(android.R.drawable.ic_dialog_alert)
                    .setPositiveButton("OK") { _, _ -> }
                    .create()
            }
        }
    }
}

enum class DialogType {
    CONFIRMATION, LOADING, ERROR
}

// Использование
val dialog = DialogFactory.createDialog(this, DialogType.CONFIRMATION)
dialog.show()

Преимущества паттерна

  • Гибкость — легко добавлять новые типы без изменения существующего кода
  • Разделение ответственности — логика создания отделена от логики использования
  • Тестируемость — можно создать Mock фабрику для тестов
  • Следование принципам SOLID — Open/Closed, Dependency Inversion
  • Полиморфизм — работаешь с интерфейсом, не с конкретным классом

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

  • Когда есть иерархия классов и нужно выбирать реализацию в runtime
  • Когда логика создания сложная или зависит от конфигурации
  • Когда планируешь расширять типы объектов в будущем
  • Когда нужна инъекция зависимостей (Dependency Injection)
Что такое паттерн Фабричный метод? | PrepBro