Ответ
Паттерн "Фабрика" (Factory Method) используется для инкапсуляции и делегирования логики создания объектов. Вместо прямого вызова конструктора с оператором new, клиентский код обращается к фабричному методу, который возвращает нужный экземпляр объекта.
Основные цели:
- Снижение связанности: Клиентский код зависит от абстракции (интерфейса/абстрактного класса), а не от конкретных классов создаваемых объектов.
- Централизация и упрощение создания: Вся сложная логика инициализации (выбор конкретного класса, конфигурация) сосредоточена в одном месте.
- Упрощение расширения: Для добавления нового типа продукта нужно изменить только код фабрики, а не все места в коде, где создаются объекты.
Пример на PHP:
// Абстракция продукта
interface Report {
public function generate(): string;
}
// Конкретные продукты
class PdfReport implements Report {
public function generate(): string {
return 'PDF report content';
}
}
class CsvReport implements Report {
public function generate(): string {
return 'CSV report content';
}
}
// Создатель с фабричным методом
abstract class ReportCreator {
// Фабричный метод
abstract public function createReport(): Report;
public function renderReport(): string {
$report = $this->createReport(); // Создание делегируется подклассам
return $report->generate();
}
}
// Конкретные создатели
class PdfReportCreator extends ReportCreator {
public function createReport(): Report {
// Здесь может быть сложная логика инициализации PdfReport
return new PdfReport();
}
}
class CsvReportCreator extends ReportCreator {
public function createReport(): Report {
return new CsvReport();
}
}
// Использование
$creator = new PdfReportCreator();
echo $creator->renderReport(); // Создаст и использует PdfReport
Таким образом, паттерн позволяет подклассам решать, объект какого конкретного класса создавать.
Ответ 18+ 🔞
Ну ты представляешь, эта твоя "Фабрика" — она как раз про то, чтобы не париться с этими вечными new на каждом углу. Вместо того чтобы в каждом месте кода, как обезьяна, тыкать new PdfReport() или new CsvReport(), ты эту поебень делегируешь специальному методу. И сидишь такой красавчик, код у тебя чистый.
Смотри, в чём прикол. Основная цель — снизить связанность, ёпта. То есть твоему основному коду, который отчёты рендерит, вообще похуй, какой там конкретный класс создаётся. Ему главное, чтобы объект был с методом generate(). А уж PdfReport это или CsvReport — это уже забота фабрики. Доверия ебать ноль к тем, кто будет этот код расширять, поэтому и прячешь логику создания.
Вторая фишка — централизация создания. Вся эта хитрая жопа с конфигурацией, выбором типа, инициализацией — она вся в одном месте, в этом фабричном методе. Не нужно по всему проекту искать, где ещё new CsvReport() захардкожен. Захотел поменять логику — пошёл в один класс и там всё сделал. Удобно же, правда?
Ну и третье — упрощение расширения. Захотел добавить, не знаю, ExcelReport — тебе не нужно перелопачивать триста файлов. Добавил новый класс отчёта и новый создатель для него. Всё, бизнес.
Пример на PHP, смотри:
// Вот это — контракт. Говорим: "Любой отчёт, мудила, должен уметь generate()"
interface Report {
public function generate(): string;
}
// Конкретные реализации. Одна в PDF, другая в CSV. Делают одно и то же, но по-разному.
class PdfReport implements Report {
public function generate(): string {
return 'PDF report content';
}
}
class CsvReport implements Report {
public function generate(): string {
return 'CSV report content';
}
}
// А вот это — основатель нашего цеха. Класс-создатель.
abstract class ReportCreator {
// А вот он, ёбаный фабричный метод! Самый сок. Абстрактный — значит, каждый подкласс будет решать сам.
abstract public function createReport(): Report;
// А это уже общая логика, которая использует то, что фабрика создаст.
public function renderReport(): string {
$report = $this->createReport(); // Магия! Не знаем что, но знаем что оно — Report.
return $report->generate();
}
}
// Конкретные начальники цехов. Каждый знает, какой отчёт ему штамповать.
class PdfReportCreator extends ReportCreator {
public function createReport(): Report {
// Тут, блядь, может быть овердохуища логики: настройки, зависимости, конфиги...
return new PdfReport();
}
}
class CsvReportCreator extends ReportCreator {
public function createReport(): Report {
// А тут может быть просто. Главное — контракт выполнить.
return new CsvReport();
}
}
// Использование. Красота!
$creator = new PdfReportCreator();
echo $creator->renderReport(); // Внутри создастся PdfReport, и всё сработает.
Короче, суть в том, что подклассы сами решают, какой объект создавать. Клиентский код (renderReport()) работает с абстракцией и ему абсолютно похуй на детали. Паттерн, конечно, не серебряная пуля, но когда у тебя логика создания начинает расползаться по проекту как тараканы — самое время задуматься о такой фабрике. Сам от себя охуеешь, насколько проще становится жить.