<?php
/*
Definice
Návrhový vzor Command zapouzdřuje jednotlivé požadavky jako objekty. Díky
tomu lze parametrizovat jiné objekty s požadavky, přidávat požadavky do fronty
a podporovat operace, které je možné provádět zpětně.
Pro implementaci tohoto návrhového vzoru jsou nutné následující kroky:
1. Definovat rozhraní pro jednotlivé příkazy.
2. Vytvořit konkrétní příkazy, které implementují rozhraní z bodu 1 a ve třídě
zapouzdřují jednotlivé požadavky.
3. Vytvořit způsob, který umožní
*/
// BAD
interface PublishingProcess {
public function publish(Publication $publication);
}
class PrintedBook implements PublishingProcess {
public function publish(Publication $publication) {
// provedení jednotlivých úkonů
}
}
class EBook implements PublishingProcess {
public function publish(Publication $publication) {
// provedení jednotlivých úkonů
}
}
// GOOD
interface BookPublishingCommand
{
public function execute(Publication $publication);
}
class CommandManuscript implements BookPublishingCommand
{
public function execute(Publication $publication)
{
printf(
"Obdržen rukopis publikace z kategorie %s, %d stran.\n",
$publication->getCategory(),
$publication->getPageCount()
);
}
}
class CommandTranslation implements BookPublishingCommand
{
public function execute(Publication $publication)
{
printf(
"Překlad publikace z kategorie %s, %d stran.\n",
$publication->getCategory(),
$publication->getPageCount()
);
}
}
class CommandProofreading implements BookPublishingCommand
{
public function execute(Publication $publication)
{
printf(
"Jazyková korektura publikace " . "z kategorie %s, %d stran.\n",
$publication->getCategory(),
$publication->getPageCount()
);
}
}
class CommandBookCover implements BookPublishingCommand
{
public function execute(Publication $publication)
{
printf(
"Příprava obálky pro publikaci " . "z kategorie %s, %d stran.\n",
$publication->getCategory(),
$publication->getPageCount()
);
}
}
class CommandAssignISBN implements BookPublishingCommand
{
public function execute(Publication $publication)
{
printf(
"Přiřazení ISBN pro publikaci " . "z kategorie %s, %d stran.\n",
$publication->getCategory(),
$publication->getPageCount()
);
}
}
class CommandPrint implements BookPublishingCommand
{
public function execute(Publication $publication)
{
printf(
"Tisk publikace z kategorie %s, %d stran.\n",
$publication->getCategory(),
$publication->getPageCount()
);
}
}
class CommandPrintToPdf implements BookPublishingCommand
{
public function execute(Publication $publication)
{
printf(
"Tisk publikace z kategorie %s, " . "%d stran do PDF souboru.\n",
$publication->getCategory(),
$publication->getPageCount()
);
}
}
class Publisher
{
protected $processes = array();
public function addProcess($name, $commands)
{
$this->processes[$name] = $commands;
}
public function publish($process, Publication $publication)
{
if (!isset($this->processes[$process])) {
throw new BookPublishingException(
"Proces '" . $process . "' neexistuje."
);
}
printf("Zahájen proces: %s.\n", $process);
foreach ($this->processes[$process] as $command) {
$command->execute($publication);
}
}
}
// USAGE
$printedBookProcess = array(
new CommandManuscript(),
new CommandProofreading(),
new CommandBookCover(),
new CommandAssignISBN(),
new CommandPrint()
);
$eBookProcess = array(
new CommandTranslation(),
new CommandProofreading(),
new CommandBookCover(),
new CommandPrintToPdf()
);
$publisher = new Publisher();
$publisher->addProcess('printedBook', $printedBookProcess);
$publisher->addProcess('eBook', $eBookProcess);
$book1 = new Book('PC', 450);
$book2 = new Journal('MEDICINA', 50);
$publisher->publish('printedBook', $book1);
$publisher->publish('eBook', $book2);
<?php
/*
Návrhový vzor Template Method definuje rozhraní algoritmu v metodě a přenechává
implementaci jednotlivých kroků potomkům třídy. Ti mohou jednotlivé části
algoritmu modifikovat, aniž by změnili jeho strukturu.
*/
abstract class AbstractPrinter implements Printer, Observable
{
// ... atributy a metody původní třídy LaserPrinter
protected $paperAmount = 150;
abstract protected function replaceCartridges();
abstract protected function checkPrintingParts();
abstract protected function isLowPaperAmount();
protected function addPaper()
{
printf(
"Doplnění %d listů do zásobníku papíru.\n",
1000 - $this->paperAmount
);
$this->paperAmount = 1000;
}
final public function check()
{
printf("Probíhá kontola tiskárny %s:\n", $this->type);
$this->replaceCartridges();
$this->checkPrintingParts();
if ($this->isLowPaperAmount()) {
$this->addPaper();
} else {
print "Dostatečné množství papíru.\n";
}
}
}
class LaserPrinter extends AbstractPrinter
{
protected function replaceCartridges()
{
print "Výměna toneru typu AAA-111.\n";
}
protected function checkPrintingParts()
{
print "Kontrola fotoválce.\n";
}
protected function isLowPaperAmount()
{
if ($this->paperAmount < 200) {
return true;
}
return false;
}
}
class InkjetPrinter extends AbstractPrinter
{
protected function replaceCartridges()
{
print "Výměna inkoustových náplní typu BBB-222.\n";
}
protected function checkPrintingParts()
{
print "Kontrola trysek.\n";
}
protected function isLowPaperAmount()
{
if ($this->paperAmount < 100) {
return true;
}
return false;
}
}
$laserPrinter = new LaserPrinter('LP-1');
$inkjetPrinter = new InkjetPrinter('IP-1');
$laserPrinter->check();
$inkjetPrinter->check();
<?php
/*
Definice
---------
Návrhový vzor Mediator odstraňuje vzájemné vazby mezi komunikujícími objekty
a tím zajišťuje možnost vzájemné komunikace mezi objekty, které nejsou v přímé
interakci. Zavedením návrhového vzoru Mediator se mění vazby mezi objekty
z typu m:n na 1:n.
Pro implementaci tohoto návrhového vzoru jsou nezbytné následující kroky:
1. Definovat rozhraní prostředníka.
2. Definovat rozhraní objektů, které budou ke komunikaci využívat objekt
definovaný v bodě 1. Toto rozhraní musí obsahovat metodu, kterou bude
volat konkrétní prostředník.
3. Implementovat konkrétního prostředníka a v něm požadovanou logiku
zabezpečující komunikaci mezi objekty. V případě, že by byla požadovaná
logika velmi komplexní, definovat pomocné třídy prostředníka.
4. Implementovat konkrétního uživatele.
Návrhový vzor Mediator je konkurenčním návrhovým vzorem
k vzoru Observer, probíranému v předchozí kapitole, avšak oproti němu nedisponuje
možnostmi dynamického přidávání a odebírání objektů zajímajících se
o změny.
*/
interface Mediator
{
public function send($message, AbstractEmployee $employee);
}
abstract class AbstractEmployee
{
protected $id;
protected $mediator;
public function __construct($id, Mediator $mediator)
{
$this->setId($id);
$this->setMediator($mediator);
}
public function setId($id)
{
$this->id = $id;
}
public function getId()
{
return $this->id;
}
public function setMediator(Mediator $mediator)
{
$this->mediator = $mediator;
}
public function getMediator()
{
return $this->mediator;
}
public function send($message)
{
$this->mediator->send($message, $this);
}
abstract public function receive($message);
}
class NewsMediator implements Mediator
{
protected $employees = array();
public function registerEmployee(AbstractEmployee $employee)
{
$this->employees[] = $employee;
}
public function send($message, AbstractEmployee $sender)
{
foreach ($this->employees as $employee) {
if ($employee !== $sender) {
$employee->receive($message);
}
}
}
}
class Employee extends AbstractEmployee
{
public function receive($message)
{
printf("<%s> Přijatá zpráva: %s\n", $this->getId(), $message);
}
}
$mediator = new NewsMediator();
$employee1 = new Employee('EMP1', $mediator);
$employee2 = new Employee('EMP2', $mediator);
$employee3 = new Employee('EMP3', $mediator);
$employee4 = new Employee('EMP4', $mediator);
$mediator->registerEmployee($employee1);
$mediator->registerEmployee($employee2);
$mediator->registerEmployee($employee3);
$mediator->registerEmployee($employee4);
$employee3->send('Zpráva od EMP3');
$employee1->send('Odpověď od EMP1');
<?php
/*
Návrhový vzor Flyweight zabezpečuje společné využívání velmi podobných objektů,
aby je bylo možné použít ve velkém počtu bez nárůstu spotřeby paměti.
Při implementaci návrhového vzoru Flyweight to neznamená, že příslušné třídy
nesmějí obsahovat žádný atribut, který by uchovával jejich stav. Při implementaci
se rozlišuje mezi vnitřním (nebo též vlastní – angl. intrinsic) a vnějším (nebo též
nevlastní – angl. extrinsic) stavem. Vnitřní stav návrhový vzor i nadále uchovává
a obsahuje výlučně informace, které jsou nezávislé na obsahu. Vnější stav je závislý
na obsahu, a proto jej nelze uchovávat a společně využívat ve třídách návrhového
vzoru Flyweight.
Definice
----------
Návrhový vzor Flyweight zabezpečuje společné využívání velmi podobných objektů,
aby je bylo možné použít ve velkém počtu bez nárůstu spotřeby paměti.
Pro implementaci návrhového vzoru Flyweight jsou nutné následující kroky:
1. Identifikovat třídu, z níž se vytváří velké množství instancí.
2. Tuto třídu osvobodit od co největšího počtu objektů, které uchovávají stav
konkrétní implementace. Tento stav instancí uložit někde mimo instance.
3. Implementovat třídu, která slouží jako zástupce „mušího“ objektu.
*/
// optimalizace pro Muší vahu :), kod z Factory kap. 3
// OLD
abstract class Cell
{
protected $content = null;
public function __construct($content)
{
$this->content = $content;
}
abstract public function show();
}
// NEW
abstract class Cell
{
abstract public function show($data);
}
// OLD
class TextCell extends Cell
{
public function show()
{
$diff = strlen($this->content) - mb_strlen($this->content, 'UTF-8');
print '|' . str_pad($this->content, 15 + $diff);
}
}
// NEW
class TextCell extends Cell
{
public function show($data)
{
$diff = strlen($data) - mb_strlen($data, 'UTF-8');
print '|' . str_pad($data, 15 + $diff);
}
}
// OLD
interface TableFactory
{
public function createCell($content);
public function createRow();
public function createHeader();
public function createTable();
}
// NEW
interface TableFactory
{
public function createCell();
public function createRow();
public function createHeader();
public function createTable();
}
// OLD
abstract class Row
{
protected $cellData = array();
public function addCell($cell)
{
$this->cellData[] = $cell;
}
abstract public function show();
}
// NEW
abstract class Row
{
protected $cellData = array();
protected $flyWeightCell;
public function __construct(Cell $cell)
{
$this->flyWeightCell = $cell;
}
// ... ostatní metody třídy
}
// OLD
class TextRow extends Row
{
public function show()
{
foreach ($this->cells as $cell) {
$cell->show();
}
print "|\n";
$str = '';
for ($i = 0; $i < count($this->cells); $i++) {
$str .= '+' . str_repeat('-', 15);
}
print $str . "+\n";
}
}
// NEW
class TextRow extends Row
{
public function show()
{
foreach ($this->cellData as $data) {
$this->flyWeightCell->show($data);
}
print "|\n";
$str = '';
for ($i = 0; $i < count($this->cellData); $i++) {
$str .= '+' . str_repeat('-', 15);
}
print $str . "+\n";
}
}
// OLD
class TextHeader extends Header
{
public function show()
{
$str = '';
for ($i = 0; $i < count($this->cells); $i++)
{
$str .= '+' . str_repeat('-', 15);
}
print $str . "+\n";
foreach ($this->cells as $cell)
{
$cell->show();
}
print "|\n";
print $str . "+\n";
}
}
// NEW
class TextHeader extends Header
{
public function show()
{
$str = '';
for ($i = 0; $i < count($this->cellData); $i++)
{
$str .= '+' . str_repeat('-',15);
}
print $str . "+\n";
foreach ($this->cellData as $data)
{
$this->flyWeightCell->show($data);
}
print "|\n";
print $str . "+\n";
}
}
// OLD
class TextTableFactory implements TableFactory
{
public function createCell($content)
{
return new TextCell($content);
}
public function createRow()
{
return new TextRow();
}
public function createHeader()
{
return new TextHeader();
}
public function createTable()
{
return new TextTable();
}
}
// NEW
class TextTableFactory implements TableFactory
{
private $cell = null;
public function createCell()
{
if (null === $this->cell) {
$this->cell = new TextCell();
}
return $this->cell;
}
public function createRow()
{
$row = new TextRow($this->createCell());
return $row;
}
public function createHeader()
{
$header = new TextHeader($this->createCell());
return $header;
}
public function createTable()
{
return new TextTable();
}
}
// OLD
class PublicationList
{
protected $tableFactory = null;
public function __construct(TableFactory $tf)
{
$this->tableFactory = $tf;
}
public function displayTable($data)
{
$table = $this->tableFactory->createTable();
$header = $this->tableFactory->createHeader();
$header->addCell($this->tableFactory->createCell('Kategorie'));
$header->addCell($this->tableFactory->createCell('Počet stran'));
$table->setHeader($header);
foreach ($data as $line) {
$row = $this->tableFactory->createRow();
foreach ($line as $field) {
$cell = $this->tableFactory->createCell($field);
$row->addCell($cell);
}
$table->addRow($row);
}
$table->show();
}
}
// NEW
class PublicationList
{
protected $tableFactory = null;
public function __construct(TableFactory $tf)
{
$this->tableFactory = $tf;
}
public function displayTable($data)
{
$table = $this->tableFactory->createTable();
$header = $this->tableFactory->createHeader();
$header->addCell('Kategorie');
$header->addCell('Počet stran');
$table->setHeader($header);
foreach ($data as $line) {
$row = $this->tableFactory->createRow();
$table->addRow($row);
foreach ($line as $field) {
$row->addCell($field);
}
}
$table->show();
}
}
// USAGE, stale stejne jen se zmenil pocet objektů
/*
Tam, kde se v původní implementaci používaly rozdílné instance třídy cz\k1886\
tables\text\TextCell, jsou nyní všude odkazy na stejnou instanci.
Tuto skutečnost můžete vidět na čísle za instancí. V tomto případě je to #5. Místo osmi
instancí této třídy tedy potřebujete už jen jednu, čímž jste zredukovali počet
potřebných instancí o 87,5 %.
Je samozřejmé, že můžete v redukování objektů pokračovat i dále a použít muší
váhu i na objekty řádků tabulky
*/
$publications = array(
array('PC', 100),
array('PC', 380),
array('medicína', 250),
array('historie', 70),
);
$pl = new PublicationList(new TextTableFactory());
$pl->displayTable($publications);
<?php
/*
Návrhový vzor Facade poskytuje zjednodušené rozhraní pro sérii rozhraní. Nabízí
rozhraní, které zjednodušuje používání základního systému.
Pro implementaci návrhového vzoru Facade jsou nutné následující kroky:
1. Identifikovat třídy a objekty systému, které mají být schované za fasádou.
2. Definovat operace, které má fasáda umožnit.
3. Implementovat třídy fasády a vytvořit metody, pomocí nichž je fasáda
schopná přistupovat ke schovaným komponentám.
4. Ve třídě fasády implementovat metody, které umožní zjednodušený přístup
k jednotlivým komponentám systému za účelem provedení různých operací.
Na první pohled se návrhový vzor Facade podobá vzoru Adapter. Avšak fasáda
se na rozdíl od adaptéru nevyužívá k přizpůsobení jednoho rozhraní druhému.
Fasáda zjednodušuje stávající rozhraní, redukuje počet tříd, které musí klient
používat, a zjednodušuje použitelnost určitého subsystému.
Fasáda rovněž prosazuje něco,
*/
/*
Příklad v knize je takový nic moc.
*/
class FacadePurchase
{
protected $library = null;
protected $publishers = array();
public function __construct(Library $library)
{
$this->library = $library;
}
public function addPublisher($id, AbstractPublisher $publisher)
{
$this->publishers[$id] = $publisher;
}
public function purchase($publisher, $pageCount)
{
if (!isset($this->publishers[$publisher])) {
throw new UnknownPublisherException('Neznámý vydavatel');
}
$publication = $this->publishers[$publisher]->sellPublication(
$pageCount
);
$id = IdGenerator::getInstance()->generateId();
$this->library->addToLibrary($id, $publication);
return $publication;
}
}
// USAGE
$debugger = DebuggerEcho::getInstance();
$library = new Library($debugger);
$bookPublisher = new BookPublisher('PC');
$journalPublisher = new JournalPublisher('medicína');
$facade = new FacadePurchase($library);
$facade->addPublisher('PC', $bookPublisher);
$facade->addPublisher('MEDICINA', $journalPublisher);
$facade->purchase('PC', 460);
$facade->purchase('MEDICINA', 300);
<?php
// https://www.supercoders.in/2019/07/php-command-line-php-parsing-program_16.html
// https://misc.flogisoft.com/bash/tip_colors_and_formatting
// https://joshtronic.com/2013/09/02/how-to-use-colors-in-command-line-output/
$longopts = array(
"required:", // Required value
"optional::", // Optional value
"option", // No value
"opt", // No value
);
$options = getopt("", $longopts);
echo "\e[0;34;41mMerry Christmas!\e[0m\n";
echo "kunda";
echo "\033[31m some colored text \033[0m some white text \n";
echo "Normal \e[5mBlink \n";
echo "Normal \e[1mBold \n";
echo "Default \e[33mYellow \n";