<?php
/*
Návrhový vzor, který vám pomůže zamezit přemnožení tříd, se nazývá Prototype
(Prototyp).
Návrhový vzor Prototype určuje způsoby vytváření objektů pomocí prototypu objektu,
který se při tvorbě nové instance zkopíruje (naklonuje).
*/
/*
Definice
Návrhový vzor Prototype určuje způsoby vytváření objektů pomocí prototypu objektu,
který se při tvorbě nové instance zkopíruje (naklonuje).
K dosažení tohoto cíle je nutné provést následující kroky:
1. Implementovat „správce prototypů“, který všechny prototypy, jež jsou
v sy sté mu dostupné, uloží a zpřístupní. Tento správce musí poskytovat způsob,
jak uložit nové prototypy pod určitým označením a následně je pod
tímto označením zpřístupnit.
2. V případě potřeby ve třídách, z nichž se budou vytvářet prototypy, implementovat
metodu __clone(). Toto je nutné jen v případě, kdy prototypy
obsahují reference na další objekty, které je nutné při klonování také klonovat.
Pokud se takovéto reference v objektu nenacházejí, potom není nutné
metodu __clone() implementovat.
3. Vytvořit a inicializovat všechny prototypy, jež lze v systému využít, a předat
je správci prototypů.
*/
class Book implements Publication
{
// ... atributy třídy
protected $cd = false;
protected $symbol = null;
// ... metody třídy
public function setCd($cd)
{
$this->cd = $cd;
}
public function hasCd()
{
return $this->cd;
}
public function setSymbol($symbol)
{
$this->symbol = $symbol;
}
public function getSymbol()
{
return $this->symbol;
}
}
class SpecialEditionPublisher
{
protected $prototype = array();
public function addSpecialEdition($edition, Publication $pr)
{
$this->prototype[$edition] = $pr;
}
public function publishPublication($edition)
{
if (!isset($this->prototype[$edition])) {
throw new UnknownSpecialEditionException(
'No prototype for special edition "' . $edition . '" registered.'
);
}
return clone $this->prototype[$edition]; // CLONE
}
}
// [1]
$bookAlaItalia = new Book('italská kuchyně', 280);
$bookAlaItalia->setSymbol('Itálie');
$bookAlaItalia->setCd(true);
// klon
$bookAlaItalia2 = clone $bookAlaItalia;
// [2]
$bookAlaItalia = new Book('italská kuchyně', 280);
$bookAlaItalia->setSymbol('Itálie');
$bookAlaItalia->setCd(true);
$journalCars = new Journal('auto-moto', 100);
$journalCars->setSymbol('Auto');
$journalCars->setCd(false);
$publisher = new SpecialEditionPublisher();
$publisher->addSpecialEdition('A La Italia', $bookAlaItalia);
$publisher->addSpecialEdition('Vozidla 20. století', $journalCars);
// Debug
$book1 = $publisher->publishPublication('A La Italia');
print 'Typ: ' . get_class($book1) . "\n";
print 'Kategorie: ' . $book1->getCategory() . "\n";
print 'Počet stran: ' . $book1->getPageCount() . "\n";
print 'Symbol: ' . $book1->getSymbol() . "\n";
print 'CD: ' . ($book1->hasCd() ? 'ano' : 'ne') . "\n";
$car1 = $publisher->publishPublication('Vozidla 20. století');
print 'Typ: ' . get_class($car1) . "\n";
print 'Kategorie: ' . $car1->getCategory() . "\n";
print 'Počet stran: ' . $car1->getPageCount() . "\n";
print 'Symbol: ' . $car1->getSymbol() . "\n";
print 'CD: ' . ($car1->hasCd() ? 'ano' : 'ne') . "\n";
/*
Typ: cz\k1886\publications\Book
Kategorie: italská kuchyně
Počet stran: 280
Symbol: Itálie
CD: ano
-----------------------------------
Typ: cz\k1886\publications\Journal
Kategorie: auto-moto
Počet stran: 100
Symbol: Auto
CD: ne
*/
// Klonovani mimo properties
/*
Návrhový vzor Prototype vyžaduje, aby všechny vaše třídy, z nichž se mají vytvářet
prototypy, šlo klonovat. To se na prvý pohled může jevit jednodušší, než jaké
je to ve skutečnosti. Obsahují-li vaše prototypy v atributech jen skalární hodnoty,
pak stačí použít operátor clone. Jsou-li však v atributech těchto tříd uložené
reference na další objekty, musíte implementovat metodu __clone(), která se
postará o vytvoření jejich kopií.
*/
class CD
{
protected $track = 1;
public function getTrack()
{
return $this->track;
}
public function setTrack($track)
{
$this->track = $track;
}
}
class Book implements Publication
{
// ... atributy třídy
protected $cd;
// ... metody třídy
public function getCd()
{
return $this->cd;
}
public function setCd(CD $cd)
{
$this->cd = $cd;
}
}
$bookAlaItalia = new Book('italská kuchyně', 280);
$bookAlaItalia->setSymbol('Itálie');
$bookAlaItalia->setCd(new CD());
$publisher = new SpecialEditionPublisher();
$publisher->addSpecialEdition('A La Italia', $bookAlaItalia);
$book1 = $publisher->publishPublication('A La Italia');
$book2 = $publisher->publishPublication('A La Italia');
print 'Aktuální stopa na CD v $book1: '
. $book1->getCd()->getTrack() . "\n";
print 'Aktuální stopa na CD v $book2: '
. $book2->getCd()->getTrack() . "\n";
/*
Aktuální stopa na CD v $book1: 1
Aktuální stopa na CD v $book2: 1
*/
$book2->getCd()->setTrack(5);
print 'Aktuální stopa na CD v $book1: '
. $book1->getCd()->getTrack() . "\n";
print 'Aktuální stopa na CD v $book2: '
. $book2->getCd()->getTrack() . "\n";
/*
Aktuální stopa na CD v $book1: 5
Aktuální stopa na CD v $book2: 5
*/
class Book implements Publication {
// ... atributy a metody třídy
public function __clone()
{
// Thats the trick!
$cd = clone $this->getCd();
$this->setCd($cd);
}
}