Kcko
4/10/2020 - 7:45 PM

19. Visitor

<?php
// Visitor

/*
Definice
--------
Návrhový vzor Visitor vám umožní přidat nové operace do struktury objektů bez
změny prvků této struktury. Operace, které se mají v této struktuře provést, jsou
zapouzdřené do nové třídy.
Pro vytvoření a použití návštěvníka i v jiných situacích jsou nutné následující
kroky:

1. Analyzovat, jaké typy prvků, které chcete rozšířit o nové funkce, se nacházejí
ve struktuře objektů.
2. Definovat rozhraní pro objekt návštěvníka s deklaracemi metod visit*()
pro každý typ prvku.
3. Do každé třídy, která se používá ve struktuře objektů, přidat metodu
acceptVisitor(), která přijme objekt implementující rozhraní z bodu 2.
V této metodě zavolat příslušnou metodu visit*() objektu návštěvníka
a předat jí aktuální objekt.
4. Projít všechny objekty, na které odkazuje aktuální objekt (poduzly), a jejich
metodě acceptVisitor()předat objekt návštěvníka.

*/


interface Publication 
{
    // ... stávající metody rozhraní
    public function acceptVisitor(Visitor $visitor);
}


interface Visitor 
{
    public function visitLibrary(Library $library);
    public function visitRentalAction(RentalAction $rentalAction);
    public function visitPublication(Publication $publication);
    public function visitMember(Member $member);
}


class Library 
{
    // ... atributy a metody třídy
    public function acceptVisitor(Visitor $visitor) 
    {
        $visitor->visitLibrary($this);

        foreach ($this->rentalActions as $rentalAction) 
        {
            $rentalAction->acceptVisitor($visitor);
        }
    }
}


class RentalAction 
{
    // ... atributy a metody třídy
    public function acceptVisitor(Visitor $visitor) 
    {
        $visitor->visitRentalAction($this);
        $this->publication->acceptVisitor($visitor);
        $this->member->acceptVisitor($visitor);
    }
}


class Member 
{
    // ... atributy a metody třídy
    public function acceptVisitor(Visitor $visitor) 
    {
        $visitor->visitMember($this);
    }
}


class VisitorEcho implements Visitor
{
    public function visitLibrary(Library $library)
    {
        print "Knihovna\n";
    }

    public function visitRentalAction(RentalAction $rentalAction)
    {
        printf(" + Publikace vypůjčená od %s", $rentalAction->getRentDate());
        if ($rentalAction->isReturned()) {
            printf(" do %s\n", $rentalAction->getReturnDate());
        } else {
            print " - dosud nevrácena\n";
        }
    }

    public function visitPublication(Publication $publication)
    {
        printf(" - Kategorie: %s\n", $publication->getCategory());
        printf(" - Počet stran: %d\n", $publication->getPageCount());
    }

    public function visitMember(Member $member)
    {
        printf(" - Čtenář: %s\n", $member->getName());
    }
}


$visitor = new VisitorEcho();
$library->acceptVisitor($visitor);



<?php

class VisitorXMLExport implements Visitor
{
    protected $doc;
    protected $root;
    protected $currentAction = null;

    public function __construct()
    {
        $this->doc = new \DOMDocument('1.0', 'UTF-8');
        $this->doc->formatOutput = true;
    }

    public function visitLibrary(Library $library)
    {
        $this->root = $this->doc->createElement('library');
        $this->doc->appendChild($this->root);
    }

    public function visitRentalAction(RentalAction $rentalAction)
    {
        $this->currentAction = $this->doc->createElement('rentalAction');
        $this->root->appendChild($this->currentAction);
        $this->currentAction->setAttribute(
            'rentDate',
            $rentalAction->getRentDate()
        );
        if ($rentalAction->isReturned()) {
            $this->currentAction->setAttribute(
                'returnDate',
                $rentalAction->getReturnDate()
            );
        }
    }

    public function visitPublication(Publication $publication)
    {
        $tag = $this->doc->createElement('publication');
        $tag->setAttribute('category', $publication->getCategory());
        $tag->setAttribute('pageCount', $publication->getPageCount());
        $this->currentAction->appendChild($tag);
    }

    public function visitMember(Member $member)
    {
        $tag = $this->doc->createElement('member');
        $tag->setAttribute('id', $member->getId());
        $tag->setAttribute('name', $member->getName());
        $this->currentAction->appendChild($tag);
    }

    public function asXML()
    {
        return $this->doc->saveXML();
    }
}


$visitor = new VisitorXMLExport();
$library->acceptVisitor($visitor);
print $visitor->asXML()