/ Gists / 14. Observe
On gists

14. Observe

Navrhove vzory - Bohmer

observer.php Raw #

<?php



/*

Definice
---------

Návrhový vzor Observer definuje závislost 1:n mezi subjektem a libovolným počtem
pozorovatelů. Při změně stavu subjektu jsou o této skutečnosti automaticky informovány
všechny pozorovatele.

Pro implementaci tohoto návrhového vzoru jsou nutné následující kroky:
1. Definovat rozhraní (Observer) pro pozorovatele, které vyžaduje jednu
metodu, prostřednictvím níž jsou pozorovatelé informovaní o změně stavu
objektu.

2. Definovat rozhraní (Observable) pro pozorované objekty. Toto rozhraní
musí vyžadovat metody na přidání a odstranění pozorovatelů a také metodu
notify(), pomocí níž jsou pozorovatele informovány o změně stavu
pozorovaného objektu. rozdílem. Pozorovatel žádné hodnoty týkající se pozorovaného objektu – je bezstavový. Tento pozorovatel
tedy může současně pozorovat více objektů. Pozorovatel naopak uchovává informaci, kdy má nastat další pravidelná kontrola – uchovává
určitý stav. Protože se tato hodnota může u různých tiskáren lišit, lze jej použít
jen pro pozorování jednoho objektu. Pro každý další objekt je nutné vytvořit nový objekt pozorovatele.

3. V pozorovaném objektu implementovat rozhraní Observable.
4. Do metod, které mění stav objektu, vložit volání metody notify().
5. Implementovat konkrétní pozorovatele.

*/


interface Printer
{
    public function turnOn();
    public function turnOff();
    public function printPublication(Publication $p, $count = 1);
    public function getType();
    public function getPageCounter();
}

interface Observable 
{
    public function attach(Observer $observer);
    public function detach(Observer $observer);
    public function notify();
}


interface Observer 
{
    public function update(Observable $observable);
}


class LaserPrinter implements Printer, Observable
{
    protected $turnedOn = false;
    protected $type = null;
    protected $pageCounter = 0;

    protected $observers = array();

    function __construct($type)
    {
        $this->type = $type;
    }

    public function turnOn()
    {
        $this->turnedOn = true;
    }

    public function turnOff()
    {
        $this->turnedOff = false;
    }

    public function getType()
    {
        return $this->type;
    }

    public function printPublication(Publication $p, $count = 1)
    {
        if (true !== $this->turnedOn) {
            return false;
        }
        $pageCount = $p->getPageCount();
        $this->pageCounter += $pageCount * $count;

        //  2 OBSERVER
        $this->notify();

        return true;
    }

    public function getPageCounter()
    {
        return $this->pageCounter;
    }

    // OBSERVE THINGS
    public function attach(Observer $observer) 
    {
        $this->observers[] = $observer;
    }
    
    public function detach(Observer $observer)
    {
        $this->observers = array_diff($this->observers, array($observer));
    }

    public function notify() 
    {
        foreach($this->observers as $observer) 
        {
            $observer->update($this);
        }
    }    
}



class ObserverInitialCheck implements Observer
{
    protected $checkPageCounter;

    public function __construct($pageCounter = 10000)
    {
        $this->checkPageCounter = $pageCounter;
    }

    public function update(Observable $observable)
    {
        if (!$observable instanceof Printer) {
            return;
        }

        if ($observable->getPageCounter() >= $this->checkPageCounter) {
            printf(
                "Nutná prvotní kontrola po %d vytištěných stranách.\n",
                $this->checkPageCounter
            );

            $observable->detach($this); 
        }
    }
}


$book = new Book('PC', 580);
$printer = new LaserPrinter('Printer 1');
$initialCheck = new ObserverInitialCheck(10000);
$printer->attach($initialCheck);
$printer->turnOn();
$printer->printPublication($book, 10);
printf("Počet vytištěných stran: %d\n",
$printer->getPageCounter());
$printer->printPublication($book, 10);
printf("Počet vytištěných stran: %d\n",
$printer->getPageCounter());
$printer->turnOff();


/*
Počet vytištěných stran: 5800
Nutná prvotní kontrola po 10000 vytištěných stranách.
Počet vytištěných stran: 11600
*/


class ObserverRegularCheck implements Observer
{
    protected $nextCheck = null;
    protected $interval;

    public function __construct($start, $interval)
    {
        $this->nextCheck = $start;
        $this->interval = $interval;
    }

    public function update(Observable $observable)
    {
        if (!$observable instanceof Printer) {
            return;
        }

        if ($observable->getPageCounter() >= $this->nextCheck) 
        {
            printf(
                "Pravidelná kontrola po %d vytištěných stranách.\n",
                $this->nextCheck
            );
            $this->nextCheck += $this->interval;
        }
    }
}



$book = new Book('PC', 580);
$printer = new LaserPrinter('Printer 1');
$initialCheck = new ObserverInitialCheck(10000);
$regularCheck = new ObserverRegularCheck(40000, 30000);
$printer->attach($initialCheck);
$printer->attach($regularCheck);
$printer->turnOn();

$printer->printPublication($book, 20);
printf("Počet vytištěných stran: %d\n",
$printer->getPageCounter());
$printer->printPublication($book, 60);

printf("Počet vytištěných stran: %d\n",
$printer->getPageCounter());
$printer->printPublication($book, 50);
printf("Počet vytištěných stran: %d\n",
$printer->getPageCounter());
$printer->turnOff();

/*
Nutná prvotní kontrola po 10000 vytištěných stranách.
Počet vytištěných stran: 11600
Pravidelná kontrola po 40000 vytištěných stranách.
Počet vytištěných stran: 46400
Pravidelná kontrola po 70000 vytištěných stranách.
Počet vytištěných stran: 75400
*/