Skip to content

Instantly share code, notes, and snippets.

@Kcko

Kcko/state.php

Created Apr 18, 2020
Embed
What would you like to do?
<?php
// State
/*
Definice
--------
Návrhový vzor State umožňuje objektu změnit chování, změní-li se jeho vnitřní
stav. Navenek se tato změna jeví, jako by objekt změnil svoji třídu.
Pro implementaci tohoto návrhového vzoru jsou nutné následující kroky:
1. V aplikaci identifikovat třídu, jejíž chování závisí na aktuálním stavu in stance.
2. Identifikovat metody odpovědné za změnu stavu a vytvořit rozhraní, které
bude obsahovat tyto metody.
3. Vytvořit způsob pro uložení aktuálního stavu objektu v původní třídě
a vytvořit metodu zabezpečující změnu aktuálního stavu.
4. Vytvořit způsob, kterým bude třída sama schopná spravovat svoje stavy. Případně
je možné spravovat jednotlivé stavy pomocí továrny nebo je implementovat
jako jedináčky.
5. Implementovat jednotlivé třídy stavů a zabezpečit přechody mezi nimi.
*/
// BAD
$printer = new LaserPrinter('Printer 1');
$book = new Book('PC', 580);
$printer->plugIn();
$printer->turnOn();
$printer->warmUp();
$printer->printPublication($book, 5);
$printer->turnOff();
$printer->unPlug();
interface Printer
{
public function plugIn();
public function unPlug();
public function turnOn();
public function turnOff();
public function warmUp();
public function printPublication(Publication $p, $count = 1);
public function getType();
public function getPageCounter();
}
/*
Implementovali jste velmi monolitické bloky kódu. Téměř každá metoda
obsahuje bloky if, které se musejí provádět jeden za druhým.
Takovýto kód není otevřený pro další rozšíření. Přijde-li v budoucnosti
požadavek, že není možné začít tisk, pokud neproběhla vnitřní diagnostika
tiskárny, budete muset kvůli doplnění jedné dodatečné podmínky změnit
několik metod.
*/
class LaserPrinter implements Printer
{
protected $plugedIn = false;
protected $turnedOn = false;
protected $warmedUp = false;
protected $type = null;
protected $pageCounter = 0;
function __construct($type)
{
$this->type = $type;
}
public function plugIn()
{
$this->plugedIn = true;
print "Tiskárna zapojena.\n";
}
public function turnOn()
{
if (true !== $this->plugedIn)
{
throw new \BadMethodCallException(
"Tiskárna nebyla zapojena do sítě."
);
}
$this->turnedOn = true;
print "Tiskárna zapnuta.\n";
}
public function warmUp()
{
if (true !== $this->plugedIn)
{
throw new \BadMethodCallException("Tiskárna nebyla zapojena do sítě.");
}
if (true !== $this->turnedOn)
{
throw new \BadMethodCallException("Tiskárna nebyla zapnuta.");
}
$this->warmedUp = true;
print "Tiskárna rozehřátá.\n";
}
public function printPublication(Publication $p, $count = 1)
{
if (true !== $this->plugedIn) {
throw new \BadMethodCallException(
"Tiskárna nebyla zapojena do sítě."
);
}
if (true !== $this->turnedOn) {
throw new \BadMethodCallException("Tiskárna nebyla zapnuta.");
}
if (true !== $this->warmedUp) {
throw new \BadMethodCallException("Tiskárna nebyla rozehřátá.");
}
$pageCount = $p->getPageCount();
$this->pageCounter += $pageCount * $count;
return true;
}
public function turnOff()
{
$this->warmedUp = false;
$this->turnedOn = false;
print "Tiskárna vypnutá.\n";
}
public function unPlug()
{
if (true === $this->turnedOn) {
throw new \BadMethodCallException("Tiskárna je pořád zapnuta.");
}
$this->plugedIn = false;
print "Tiskárna odpojena.\n";
}
public function getType()
{
return $this->type;
}
public function getPageCounter()
{
return $this->pageCounter;
}
}
// GOOD, pattern STATE
interface PrinterState
{
const STATE_OFFLINE = 0;
const STATE_PLUGED_IN = 1;
const STATE_TURNED_ON = 2;
const STATE_WARMED_UP = 3;
public function setState(PrinterState $state);
public function getState($stateId);
public function plugIn();
public function turnOn();
public function warmUp();
public function printPublication(Publication $p, $count = 1);
public function turnOff();
public function unPlug();
}
class LaserPrinter implements Printer
{
protected $state;
protected $states = array();
protected $type = null;
protected $pageCounter = 0;
function __construct($type)
{
$this->type = $type;
$this->states[Printer::STATE_OFFLINE] = new OfflinePrinterState($this);
$this->states[Printer::STATE_PLUGED_IN] = new PlugedInPrinterState($this);
$this->states[Printer::STATE_TURNED_ON] = new TurnedOnPrinterState($this);
$this->states[Printer::STATE_WARMED_UP] = new WarmedUpPrinterState($this);
$this->state = $this->getState(Printer::STATE_OFFLINE);
}
public function plugIn()
{
$this->state->plugIn();
}
public function turnOn()
{
$this->state->turnOn();
}
public function warmUp()
{
$this->state->warmUp();
}
public function printPublication(Publication $p, $count = 1)
{
$pageCount = $this->state->printPublication($p, $count);
if (false !== $pageCount) {
$this->pageCounter += $pageCount;
}
}
public function turnOff()
{
$this->state->turnOff();
}
public function unPlug()
{
$this->state->unPlug();
}
public function getType()
{
return $this->type;
}
public function getPageCounter()
{
return $this->pageCounter;
}
public function getState($stateId)
{
return $this->states[$stateId];
}
public function setState(PrinterState $state)
{
printf("Tiskárna měni stav: %s.\n", get_class($state));
$this->state = $state;
}
}
abstract class AbstractPrinterState implements PrinterState
{
protected $printer;
public function __construct(Printer $printer)
{
$this->printer = $printer;
}
}
class OfflinePrinterState extends AbstractPrinterState
{
public function plugIn()
{
$this->printer->setState(
$this->printer->getState(Printer::STATE_PLUGED_IN)
);
print "Tiskárna zapojena do sítě.\n";
}
public function turnOn()
{
throw new \BadMethodCallException("Tiskárna nebyla zapojena.\n");
}
public function warmUp()
{
throw new \BadMethodCallException("Tiskárna nebyla zapnuta.\n");
}
public function printPublication(Publication $p, $count = 1)
{
throw new \BadMethodCallException("Není možné.\n");
}
public function turnOff()
{
throw new \BadMethodCallException("Tiskárna nebyla zapnuta.\n");
}
public function unPlug()
{
throw new \BadMethodCallException("Tiskárna nebyla zapojena.\n");
}
}
class PlugedInPrinterState extends AbstractPrinterState
{
public function plugIn()
{
throw new \BadMethodCallException("Tiskárna již byla zapojena.\n");
}
public function turnOn()
{
$this->printer->setState(
$this->printer->getState(Printer::STATE_TURNED_ON)
);
print "Tiskárna zapnuta.\n";
}
public function warmUp()
{
throw new \BadMethodCallException("Tiskárna nebyla zapnuta.\n");
}
public function printPublication(Publication $p, $count = 1)
{
throw new \BadMethodCallException("Není možné.\n");
}
public function turnOff()
{
throw new \BadMethodCallException("Tiskárna nebyla zapnuta.\n");
}
public function unPlug()
{
$this->printer->setState(
$this->printer->getState(Printer::STATE_OFFLINE)
);
print "Tiskárna odpojena.\n";
}
}
class TurnedOnPrinterState extends AbstractPrinterState
{
public function plugIn()
{
throw new \BadMethodCallException("Tiskárna již byla zapojena.\n");
}
public function turnOn()
{
throw new \BadMethodCallException("Tiskárna již byla zapnuta.\n");
}
public function warmUp()
{
$this->printer->setState(
$this->printer->getState(Printer::STATE_WARMED_UP)
);
print "Tiskárna rozehřátá.\n";
}
public function printPublication(Publication $p, $count = 1)
{
throw new \BadMethodCallException("Není možné.\n");
}
public function turnOff()
{
$this->printer->setState(
$this->printer->getState(Printer::STATE_PLUGED_IN)
);
print "Tiskárna vypnutá.\n";
}
public function unPlug()
{
throw new \BadMethodCallException("Tiskárna je pořád zapnutá.\n");
}
}
class WarmedUpPrinterState extends AbstractPrinterState
{
public function plugIn()
{
throw new \BadMethodCallException("Tiskárna již byla zapojena.\n");
}
public function turnOn()
{
throw new \BadMethodCallException("Tiskárna již byla zapnuta.\n");
}
public function warmUp()
{
throw new \BadMethodCallException("Tiskárna již byla rozehřáta.\n");
}
public function printPublication(Publication $p, $count = 1)
{
$pageCount = $p->getPageCount() * $count;
printf("Vytištěných %d stran.\n", $pageCount);
return $pageCount;
}
public function turnOff()
{
$this->printer->setState(
$this->printer->getState(Printer::STATE_PLUGED_IN)
);
print "Tiskárna vypnutá.\n";
}
public function unPlug()
{
throw new \BadMethodCallException("Tiskárna je pořád zapnutá.\n");
}
}
// USAGE
$printer = new LaserPrinter('Printer 1');
$book = new Book('PC', 580);
$printer->plugIn();
$printer->turnOn();
$printer->warmUp();
$printer->printPublication($book, 5);
$printer->turnOff();
$printer->unplug();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.