Ответ
Оба паттерна относятся к порождающим, но решают разные задачи создания объектов.
Factory (Фабрика): Сосредоточена на инкапсуляции логики выбора конкретного класса для создания. Ее цель — скрыть детали инстанцирования от клиента.
- Акцент: «Что» создать.
- Процесс: Создание объекта обычно происходит в один шаг.
- Используется, когда есть общий интерфейс или базовый класс и несколько конкретных реализаций, выбор между которыми зависит от условий.
// Простая фабрика
protocol Vehicle {
func drive()
}
class Car: Vehicle { /* ... */ }
class Truck: Vehicle { /* ... */ }
enum VehicleFactory {
static func makeVehicle(for load: Int) -> Vehicle {
// Логика выбора конкретного класса
return load > 1000 ? Truck() : Car()
}
}
// Клиентский код
let vehicle = VehicleFactory.makeVehicle(for: 500)
vehicle.drive() // Не знает, создалась Car или Truck
Builder (Строитель): Сосредоточен на пошаговом конструировании сложного объекта с множеством возможных конфигураций. Отделяет процесс построения от его представления.
- Акцент: «Как» создать, с какими параметрами.
- Процесс: Пошаговое конфигурирование, часто с использованием fluent-интерфейса (цепочка вызовов), финализируемое методом
build(). - Используется, когда объект имеет много опциональных или взаимозависимых полей, и его создание в одном конструкторе было бы громоздким (телескопический конструктор).
// Builder для сложного объекта
class Pizza {
let size: Size
let cheese: Bool
let pepperoni: Bool
// ... много других свойств
// Инициализатор может быть private
init(builder: PizzaBuilder) { /* ... */ }
}
class PizzaBuilder {
private var size: Size = .medium
private var cheese = true
private var pepperoni = false
func setSize(_ size: Size) -> PizzaBuilder {
self.size = size
return self // Fluent interface
}
func addPepperoni() -> PizzaBuilder {
self.pepperoni = true
return self
}
func removeCheese() -> PizzaBuilder {
self.cheese = false
return self
}
func build() -> Pizza {
// Здесь может быть валидация параметров
return Pizza(builder: self)
}
}
// Клиентский код
let pizza = PizzaBuilder()
.setSize(.large)
.addPepperoni()
.removeCheese()
.build() // Объект создается здесь
Итог: Используйте Factory, когда нужно делегировать выбор класса. Используйте Builder, когда нужно гибко и наглядно конфигурировать сложный объект.