Паттерн Factory
Часть раздела Объектно-ориентированное программирование путешествия по PHP на Coddy. Урок 72 из 91.
Factory Pattern — это порождающий шаблон проектирования, который делегирует создание объектов отдельному class или method. Вместо того чтобы напрямую использовать new по всему коду, вы просите factory создавать объекты за вас.
Этот шаблон особенно полезен, когда у вас есть несколько связанных class, которые используют общий interface, и вы хотите решить, какой из них создать, основываясь на некотором условии. Рассмотрим систему notification, которая может send сообщения через разные каналы:
<?php
interface Notification {
public function send(string $message): string;
}
class EmailNotification implements Notification {
public function send(string $message): string {
return "Email: $message";
}
}
class SmsNotification implements Notification {
public function send(string $message): string {
return "SMS: $message";
}
}
Без фабрики тебе пришлось бы повсюду разбрасывать операторы if и вызовы new. Фабрика централизует эту логику:
<?php
class NotificationFactory {
public static function create(string $type): Notification {
return match($type) {
'email' => new EmailNotification(),
'sms' => new SmsNotification(),
default => throw new InvalidArgumentException("Unknown type: $type")
};
}
}
$notification = NotificationFactory::create('email');
echo $notification->send('Hello!');
Output:
Email: Hello!Ключевое benefit заключается в том, что ваш код зависит от interface Notification, а не от конкретных классов. Если позже вы добавите class PushNotification, вам нужно будет обновить только фабрику. Весь код, использующий фабрику, автоматически получит доступ к новому типу без изменений.
Задание
ЛегкоДавайте создадим систему генерации document с использованием шаблона Factory. Разные типы document (PDF, HTML, Plain Text) используют общий interface, но создают разные результаты: идеальный сценарий для централизации создания объектов в factory.
Вы организуете код в четырёх файлах:
Document.php: Создайте interfaceDocument, определяющий контракт, которому должны следовать все типы document. В нём должен быть единственный methodrender(string $content): string, который принимает content и возвращает отформатированный результат document.Documents.php: Подключите interface Document и создайте три класса, которые его реализуют:PdfDocument: Егоrender()method возвращает"PDF: [content]"HtmlDocument: Егоrender()method возвращает"<html>[content]</html>"TextDocument: Егоrender()method возвращает"TXT: [content]"
DocumentFactory.php: Подключите файл Documents и создайте классDocumentFactoryсо static methodcreate(string $type): Document. Этот method должен использоватьmatch, чтобы возвращать соответствующий объект document в зависимости от типа:"pdf"возвращает новыйPdfDocument"html"возвращает новыйHtmlDocument"text"возвращает новыйTextDocument- Для любого другого типа следует выбросить
InvalidArgumentExceptionс message"Unknown document type: [type]"
main.php: Подключите файл DocumentFactory. Вы получите два входных значения: тип document и content для рендеринга.Используйте factory, чтобы создать подходящий тип document, затем вызовите его
render()method с content и выведите result.С новой строки выведите
"Factory benefit: Adding new types only requires updating the factory", чтобы подчеркнуть ценность этого шаблона.
Шаблон Factory сохраняет ваш код гибким: когда позже понадобится добавить MarkdownDocument, вы обновите только factory, а весь существующий код продолжит работать без изменений.
Попробуйте сами
<?php
require_once 'DocumentFactory.php';
// Прочитать ввод
$type = trim(fgets(STDIN));
$content = trim(fgets(STDIN));
// TODO: Используйте DocumentFactory для создания соответствующего типа документа
// TODO: Вызовите метод render() с содержимым и выведите результат
// TODO: On a new line, print "Factory benefit: Adding new types only requires updating the factory"
?>В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово $thisМетодыСвойстваКонструктор (__construct)Деструктор (__destruct)Повторение — простой калькулятор4Наследование
Основы наследованияКлючевое слово parent::Переопределение методовКлючевое слово finalАбстрактные классыПовторение — иерархия сотрудников7Инкапсуляция
Public, Protected, PrivateМодификаторы доступа подробноГеттеры и сеттерыСокрытие информацииПродвижение конструктора (8.0)Повторение — система учёта студентов2Пространства имён и автозагрузка
Введение в пространства имёнКлючевое слово useСтандарт автозагрузки PSR-4Автозагрузчик ComposerПовторение — структурированный проект5Интерфейсы и контракты
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовИнтерфейс и абстрактный классАннотация типов с интерфейсамиПовторение — калькулятор фигур8Магические методы
Введение в магические методы__toString и __debugInfo__get, __set, __isset, __unset__call и __callStatic__clone и клонирование объектов__serialize и __unserializeПовторение — пользовательская коллекция3Свойства классов
Свойства экземпляра и статические свойстваКонстанты в классахСтатические методы и свойстваПриватные и защищённые свойстваСвойства только для чтения (PHP 8.1)Повторение — менеджер банковского счёта6Полиморфизм
Повторение переопределения методовПолиморфизм через интерфейсыАннотации типов и объединённые типыПозднее статическое связываниеПовторение — обработчик платежей9Трейты
Введение в трейтыИспользование нескольких трейтовРазрешение конфликтов трейтовАбстрактные методы в трейтахТрейты и наследование12Паттерны проектирования, часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн StrategyПотренируйтесь самостоятельно: Онлайн-компилятор PHP