Паттерн «Посетитель» в Laravel

Паттерн программирования Посетитель

Laravel Visitor — это реализация паттерна программирования «Посетитель» для фреймворка Laravel. Он позволяет легко выполнить обработку набора произвольных элементов, без необходимости использования повторяющихся условных выражений, тем самым улучшая абстракцию кода.

Без «Посетителя»

public function process()
{
    $result = '';
    foreach ($this->elements as $element) {
        if ($element instanceof FooClass) {
            $result .= ((FooClass)$element)->getData();
        } elseif ($element instanceof BarClass) {
            $result .= ((BarClass)$element)->getData();
        } elseif ($element instanceof BazClass) {
            $result .= ((BazClass)$element)->getData();
        }
    }
}

C «Посетителем»

public function process()
{
    $visitor = new MyVisitor([
                                 new FooClass(),
                                 new BarClass(),
                                 new BazClass(),
                             ]);

    $visitor->execute();

    $result = $visitor->getResult();
}

Вся сложность сокрыта в классе MyVisitor, который определяет методы для обработки классов. Для предыдущего примера, MyVisitor будет реализован так:

class MyVisitor extends Visitor
{
    private $result;

    public function getResult()
    {
        return $this->result();
    }

    public function visitFooClass(FooClass $fooClass)
    {
        $this->result .= ... ;
    }

    public function visitBarClass(BarClass $fooClass)
    {
        $this->result .= ... ;
    }

    public function visitBazClass(BazClass $fooClass)
    {
        $this->result .= ... ;
    }
}

Это обеспечивает соблюдение SRP (Принципа Единой Ответственности), поскольку Доменные Объекты не должны реализовывать репрезентативные методы, за которые отвечают только реализации классов Visitor (особенно, если их требуется несколько).

Использование

Для использования пакета необходимо определить как минимум один класс Visitor и несколько классов Visitee.

Реализация Visitee

Единственное требование для классов Visitee — использование трейт Visitable, что сделает класс пригодным для использования паттерна.

Реализация Visitor

Класс Visitor должен реализовывать интерфейс CanVisit и абстрактный подкласс Visitor, определяя метод getResult().

Кроме того, для каждого определенного Visitee вы должны реализовать метод обработки по вашему выбору.
Например, если у вас есть Book Visitee, вы должны определить метод:

public function visitBook(Book $book) {
  ...
}

Генерация Visitor

Для генерации «Посетителя» вы можете запустить следующую команду:

php artisan make:visitor MyVisitor

по умолчанию она создаёт классы в папке Visitors.

Пример использования

Реализация Visitee

Magazine.php

use robertogallea\LaravelVisitor\Models\Visitable;

class Magazine
{
    use Visitable;

    private $title;
    private $month;
    private $year;

    public function __construct($title, $month, $year)
    {
        $this->title = $title;
        $this->month = $month;
        $this->year = $year;
    }

    public function getTitle()
    {
        return $this->title;
    }

    public function getMonth()
    {
        return $this->month;
    }

    public function getYear()
    {
        return $this->year;
    }

}

Реализация Visitor

XMLVisitor.php

use robertogallea\LaravelVisitor\Models\Visitor;

class XMLVisitor extends Visitor
{
    private $xml = '';

    public function visitMagazine(Magazine $magazine)
    {
        $this->xml .= '<magazine title="' . $magazine->getTitle() . '" ' .
            'issue="' . $magazine->getMonth() . ' ' . $magazine->getYear() . '"></magazine>' . "\n";
    }

    public function getResult()
    {
        return $this->xml;
    }
}

 

Клиентский код

$xmlCatalog = new XMLVisitor([
    new Magazine('PHP programming', 'July', 2019),
    new Magazine('The art of woodworking', 'August', 2019)
]);

$xmlCatalog->process();

echo ($xmlCatalog->getResult());

выведет следующее:

<magazine title="PHP programming" issue="July 2019"></magazine>
<magazine title="The art of woodworking" issue="August 2019"></magazine>

Репозиторий на Github: https://github.com/robertogallea/Laravel-Visitor

Автор: Roberto Gallea
Перевод: Алексей Широков

Наши Телеграм и Вконтакте — следите за выходом новых статей через наши каналы.

Задать вопросы по урокам можно на нашем форуме.