Factory паттерн

Тренажер по PHP для пользователей с начальным уровнем подготовки.

Тренажер PHP

Паттерн "Фабричный метод" (Factory Method) — это один из самых популярных порождающих паттернов проектирования. Его главная идея — делегировать создание объектов дочерним классам. Вместо того чтобы вызывать оператор `new` напрямую в клиентском коде, мы вызываем специальный "фабричный" метод. Это позволяет системе оставаться гибкой: в будущем можно легко добавлять новые типы продуктов, не изменяя код, который их использует.

В этом тренажере мы разберем структуру паттерна, научимся определять его ключевые компоненты, соберем с нуля простую фабрику, исправим типичные ошибки в ее реализации и научимся предсказывать, какой объект будет создан в зависимости от переданных условий. Это поможет вам понять, как инкапсулировать логику создания объектов и сделать ваш код более расширяемым и поддерживаемым.

Список тем

Сопоставьте компоненты Фабричного метода с их ролями

id: 39359_task_factory_1

Паттерн "Фабричный метод" состоит из нескольких ключевых частей. Каждая выполняет свою уникальную роль. Сопоставьте название каждого компонента в левой колонке с его правильным описанием в правой колонке.

Сопоставьте строки в правой части с соответствующими строками в левой по порядковому номеру
Product (Продукт)
ConcreteProduct (Конкретный продукт)
Creator (Создатель)
ConcreteCreator (Конкретный создатель)
Класс, который реализует интерфейс Продукта.
Класс, который переопределяет фабричный метод для создания экземпляра Конкретного продукта.
Интерфейс для объектов, которые создает фабричный метод.
Абстрактный класс, который объявляет фабричный метод, возвращающий объект типа Продукт.
Сообщения
Проверить
Показать подсказку

Определите интерфейс и продукт

id: 39359_task_factory_2

Прежде чем создавать фабрику, нужно определить, что она будет производить. Заполните пропуски, чтобы создать интерфейс `Logger` и его конкретную реализацию `FileLogger`, которая будет соответствовать этому интерфейсу.

Заполните пропуски
interface Logger 
{
    public function input1S(string $message);
}

class FileLogger input2S Logger 
{
    public function log(input3S $message)
    {
        echo "Logging to file: " . $message;
    }
}
Сообщения
Проверить
Показать решение на 3 сек.
Показать подсказку

Исправьте ошибку в объявлении фабрики

id: 39359_task_factory_3

Вот абстрактная фабрика, которая объявляет метод для создания логгеров. Однако в коде есть ошибка, которая не позволит дочерним классам переопределить фабричный метод. Найдите и исправьте ее.

Найдите ошибку и исправьте
interface Logger 
{
    public function log(string $message);
}
 
abstract class LoggerFactory
{
    abstract private function createLogger(): Logger {};
 
    public function logMessage(string $message): void
    {
        $logger = $this->createLogger();
        $logger->log($message);
    }
}
Сообщения
Проверить
Показать решение на 3 сек.
Показать подсказку

Соберите простую фабрику автомобилей

id: 39359_task_factory_4

Из перемешанных строк кода соберите полную рабочую реализацию паттерна "Фабричный метод". Код должен определять интерфейс, конкретный продукт, конкретную фабрику и вызывать ее для создания объекта. Некоторые строки могут быть лишними.

Перетяните в правильном порядке строки из одного блока в другой
class Car implements Vehicle { public function drive() { echo "Driving a car..."; } }
$carFactory = new CarFactory();
interface Vehicle { public function drive(); }
class CarFactory { public function createVehicle(): Vehicle { return new Car(); } }
$car = $carFactory->createVehicle();
$car->drive();
<?php
return new Vehicle();
class Truck { }
Сообщения
Проверить
Показать решение на 3 сек.
Показать подсказку

Заполните логику фабрики уведомлений

id: 39359_task_factory_5

Перед вами каркас фабрики, которая должна создавать разные типы уведомений (`EmailNotifier` или `SmsNotifier`) в зависимости от переданного типа. Заполните пропуски в `switch` конструкции, используя токены из банка.

Нужно правильно расставить в пропуски предложенные варианты
class NotifierFactory
{
    public function createNotifier(string $type): Notifier
    {
        switch ($type) {
            input1S
                input2S;
            case 'sms':
                return new SmsNotifier();
            input3S
                input4S("Unknown notifier type");
        }
    }
}
case 'email':
return new EmailNotifier();
default:
throw new InvalidArgumentException
case 'http':
break;
Сообщения
Проверить
Показать решение на 3 сек.
Показать подсказку

Какой результат выведет код?

id: 39359_task_factory_6

Проанализируйте код, который использует фабрику для создания геометрических фигур. Определите, какой объект будет создан и что выведет на экран вызов его метода. Впишите результат в поле ответа.

Что должно получиться?
interface Shape {
    public function draw();
}
class Circle implements Shape {
    public function draw() { echo "Drawing a circle"; }
}
class Square implements Shape {
    public function draw() { echo "Drawing a square"; }
}
class ShapeFactory {
    public function createShape(string $type): Shape {
        return match ($type) {
            'circle' => new Circle(),
            'square' => new Square(),
        };
    }
}

$factory = new ShapeFactory();
$shape = $factory->createShape('square');
$shape->draw();
Сообщения
Проверить
Показать подсказку

Найдите логическую ошибку в фабрике

id: 39359_task_factory_7

Эта фабрика должна создавать разные объекты для подключения к базам данных. Однако из-за ошибки "копипаста" она всегда будет пытаться создать один и тот же тип объекта, даже если запрошен другой. Найдите и исправьте логическую ошибку в условии.

Найдите ошибку и исправьте
// ... (интерфейс Connection и классы MysqlConnection, PostgresConnection)
class ConnectionFactory
{
    public function createConnection(string $driver): Connection
    {
        if ($driver === 'mysql') {
            return new MysqlConnection();
        } elseif ($driver === 'mysql') {
            return new PostgresConnection();
        } else {
            throw new Exception("Driver not supported.");
        }
    }
}
Сообщения
Проверить
Показать решение на 3 сек.
Показать подсказку

Распределите классы и интерфейсы по их ролям

id: 39359_task_factory_8

Ниже представлен набор классов и интерфейсов из системы, использующей паттерн Фабричный метод. Распределите их по трем категориям: "Продукты" (конкретные классы), "Интерфейс продукта" (общий контракт) и "Создатель" (фабрика).

Перетяните элементы в соответствующие блоки
Продукты
Интерфейс продукта
Создатель (Фабрика)
Не относится к паттерну
EmailMessage
SmsMessage
MessageFactory
Message
User
Сообщения
Проверить
Показать подсказку

Что произойдет при вызове с неверным типом?

id: 39359_task_factory_9

Фабрика умеет создавать объекты `PdfExporter` и `CsvExporter`. Что произойдет, если попытаться создать экспортер с типом 'xml', который не поддерживается фабрикой? Выберите правильный вариант.

Выберите правильный вариант ответа
class ExporterFactory
{
    public function create(string $format): Exporter
    {
        switch ($format) {
            case 'pdf':
                return new PdfExporter();
            case 'csv':
                return new CsvExporter();
            default:
                throw new \InvalidArgumentException('Format not supported.');
        }
    }
}

$factory = new ExporterFactory();
$exporter = $factory->create('xml');
Сообщения
Проверить
Показать подсказку
НайтиКурс.Ру