Menu
Coddy logo textTech

Паттерн 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, вам нужно будет обновить только фабрику. Весь код, использующий фабрику, автоматически получит доступ к новому типу без изменений.

challenge icon

Задание

Легко

Давайте создадим систему генерации document с использованием шаблона Factory. Разные типы document (PDF, HTML, Plain Text) используют общий interface, но создают разные результаты: идеальный сценарий для централизации создания объектов в factory.

Вы организуете код в четырёх файлах:

  • Document.php: Создайте interface Document, определяющий контракт, которому должны следовать все типы document. В нём должен быть единственный method render(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 method create(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"

?>
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор PHP