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
Перевод: Алексей Широков
Наш Телеграм-канал — следите за новостями о Laravel.