Ответ
Оба паттерна относятся к порождающим, но решают разные задачи создания объектов.
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, когда нужно гибко и наглядно конфигурировать сложный объект.
Ответ 18+ 🔞
Давай разжую, как есть, без соплей. Оба паттерна — про создание объектов, но мозги они ебут по-разному, вот в чём соль.
Фабрика (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() // Поехал, а на чём — похуй, это фабрикина головная боль
Строитель (Builder) — это уже другая, блядь, опера. Тут объект не «выбирается», а «собирается по кирпичикам». Представь, что ты заказываешь пиццу: размер, сыр, колбаса, грибы, ананасы, мать их... И если всё это запихнуть в один конструктор, получится пиздец на 15 параметров, половина из которых опциональны. Вот строитель как раз позволяет настраивать всё пошагово, красиво, с цепочкой вызовов. Акцент на «КАК» создать, с какими опциями.
// Строитель для этой вашей многокомпонентной хуйни
class Pizza {
let size: Size
let cheese: Bool
let pepperoni: Bool
// ... и ещё овердохуища свойств
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-интерфейс, цепочка
}
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() // И только здесь пицца материализуется
Короче, резюме, чтобы не ебать мозг:
- Тыкаешь в Фабрику, когда тебе нужно, чтобы кто-то умный за тебя выбрал конкретный класс из кучи вариантов. «Сделай мне транспорт» — и поехал.
- Хватаешься за Строитель, когда объект — сложная хуйня с кучей настроек, и ты хочешь собирать его поэтапно, как конструктор. «Дайте пиццу, но без сыра, зато с перцем и оливками» — вот это его стезя.
Всё. Выбор за тобой, просто не путай, а то получится ебушки-воробушки.