post_ico4

Wzorce projektowe, cz. 3 Prototype

Trzecia część z serii wpisów o wzorcach projektowych. Tym razem omówię wzorzec projektowy Prototyp (Prototype).

Prototyp jest wzorcem, opisującym mechanizm tworzenia nowych obiektów poprzez klonowanie jednego obiektu macierzystego. Mechanizm klonowania wykorzystywany jest wówczas, gdy należy wykreować dużą liczbę obiektów tego samego typu lub istnieje potrzeba tworzenia zbioru obiektów o bardzo podobnych właściwościach.


Diagram klas wzorca Prototype

Implementując ten wzorzec deklaruje się klasę Prototype z abstrakcyjną operacją klonującą clone(). Operacja ta jest implementowana w klasach dziedziczonych po Prototype. Klient chcąc stworzyć nowy obiekt wywołuje metodę clone() pośrednio, za pomocą zdefiniowanej przez siebie operacji z parametrem określającym wymaganą docelową klasę realizującą abstrakcję Prototype.

Przykładowa implementacja

<?php
abstract class Prototype{
    protected $name;

    public function __construct($name) {
        $this->name=$name;
    }
    abstract function __clone();
    public function getName() {
        return $this->name;
    }
}

class ConcretePrototype extends Prototype{

    public function __construct($name) {
        parent::__construct($name);
    }
    public function __clone() {}
}

// testy
$prototype = new ConcretePrototype("nazwa");
echo  $prototype->getName(); // wyswietli "nazwa"
$prototype2 = clone $prototype;
echo  $prototype2->getName(); // wyswietli "nazwa"
?>

Przykład z życia wzięty

Przypuśćmy, że tworzymy księgarnię internetową. Istnieje potrzeba stworzenia wielu obiektów książek o podobnych właściwościach (wspólna kategoria, autor itp.). Zamiast ustawiać pola dla każdego obiektu oddzielnie możemy wykonać klony i zmieniać tylko elementy unikalne.

<?php
abstract class Book {
    protected $title;
    protected $topic;
    abstract function __clone();
    public function getTitle() {
        return $this->title;
    }
    public function setTitle($title) {
        $this->title = $title;
    }
    public function getTopic() {
        return $this->topic;
    }
}

class PHPBook extends Book {
    public function __construct() {
        $this->topic = 'PHP';
    }
    function __clone() {
    }
}

class JAVABook extends Book {
    public function __construct() {
        $this->topic = 'JAVA';
    }
    function __clone() {
    }
}

//testy
$phpbook1 = new PHPBook();
$phpbook1->setTitle("Ksiazka1");
$phpbook2 = clone $phpbook1;
$phpbook2->setTitle("Ksiazka2");

$javabook1 = new JAVABook();
$javabook1->setTitle("Ksiazka1");
$javabook2 = clone $javabook1;
$javabook2->setTitle("Ksiazka2");

echo "Kategoria: ".$phpbook1->getTopic()." Tytul: ".$phpbook1->getTitle()."<br />";
echo "Kategoria: ".$phpbook2->getTopic()." Tytul: ".$phpbook2->getTitle()."<br />";
echo "Kategoria: ".$javabook1->getTopic()." Tytul: ".$javabook1->getTitle()."<br />";
echo "Kategoria: ".$javabook2->getTopic()." Tytul: ".$javabook2->getTitle()."<br />";
?>

Zastosowanie

Wzorzec Prototype można stosować w sytuacjach, gdy tworzona jest duża liczba obiektów tego samego typu. Stosuje się go głównie w celach optymalizacji, gdyż klonowanie obiektu jest szybsze niż jego stworzenie.

PS: Może ktoś napisze miarodajne testy? ;)

Powiązane tematy

Co sądzisz o wpisie?
BeżnadziejnySłabyŚredniDobryBardzo dobry (Brak ocen, bądź pierwszy!)
Loading...
  • hitman

    Dziękuję, bardzo pomocne

  • thek

    Ja mam z kolei pytanie natury bardziej ogólnej. Cykl wzorców będzie zawierał jakiś konkretny typ, czy ogólnie te będące popularne, powszechne wzorce? Jak na razie bowiem widzę, że zawarłeś opis dwóch konstrukcyjnych (Singleton i Prototyp) oraz jednego operacyjnego (Strategia). Domyślam się iż wystąpią na pewno pozostałe konstrukcyjne (Budowniczy, Fabryka abstrakcyjna i Metoda wytwórcza), kilka operacyjnych (Iterator, Obserwator, Pamiątka, Stan) i zapewne choć jeden ze strukturalnych (przynajmniej Kompozyt, ale może i Dekoratora czy Fasadę). Może więc jest jakiś sens w usystematyzowaniu tego?

    Poza tym jeśli jesteśmy przy wzorcach konstrukcyjnych można, po przedstawieniu wszystkich, pokusić się o wyszczególnienie ich wad i zalet oraz jakieś przypadki rozważyć,kiedy jedno rozwiązanie jest lepsze niż inne do zastosowania. Bo jakby nie spojrzeć, wzorce konstrukcyjne są w wielu przypadkach konkurencją dla siebie. Właśnie najlepiej to jest widoczne przypadku Prototypu i Fabryki abstrakcyjnej, które mają wspólne pewne pola działania.

  • W planach mam zawarcie wzorców różnych typów (kreacyjne, operacyjne itp) – najbardziej przydatne w programowaniu aplikacji internetowych :)

    Hmm można później pomyśleć nad jakimś spisem treści, by trochę usystematyzować (narazie jest 3, więc za mało by w to się bawić). A z tym porównywaniem dobry pomysł. Na koniec napiszę to w podsumowaniu cyklu.

    Cały cykl chyba będzie się składał z 10-12 części, ale to nie jest jeszcze w 100% pewne ;)

  • zenon

    fajnie jak bys opisywal znacznie wiecej realnych zastosowan i przykladow z zycia wzietych. pro programisci pewnie je znaja ale pro znaja dokladnie tez wzorce wiec o nich nie czytaja a maluczkim by sie to pewnie przydalo i bardziej przemawialo niz sucha definicja ;]

  • thek

    Pewne w 100% być nie może, zwłaszcza że książka „bandy czworga” wyszczególnia ich trochę (24) i pokrywa się z listą wzorców projektowych w wikipedii (nawet kolejność identyczna ;) ). Nie ma jednak w książce ostatniego z Wiki oraz choćby Property z 4 części cyklu. Ale to nie dziwne, bo przecież książka ma, mimo kolejnych wydań, już „parę lat” i trochę się pozmieniało od tego czasu. Ogólnie jak sami autorzy napisali, ich książka jest tylko wskazaniem drogi i powinny powstawać nowe oraz obecne można krytykować.

  • Ano wszystkich na pewno nie będzie – jest ich wiele ;) Skupię się tylko na najbardziej popularnych i przydatnych w PHP.

    @Zenon
    Staram się pisać jak najprostsze i z życia wzięte przykłady. Żeby przeanalizować po kilka przykładów dla każdego wzorca musiałbym chyba książkę napisać :P Na pewno będą jeszcze przykłady w podsumowaniu, tak jak @thek zasugerował

  • thek

    I wyszła by Ci, uaktualniona o będące teraz w użyciu wzorce, książka porównywalna do „bandy czworga” ;) Swoją drogą czytam ją sobie czasem, gdy coś mi nagle nie pasuje.

  • kuna

    genialna stronka.

  • Daniel

    A czy nie lepiej w klasach PHP i Java ustawić wartość zmiennej w kodzie a nie w konstruktorze ?

    • W jaki sposób ustawisz jest bez większej różnicy. W przykładzie zdecydowałem się na konstruktor, ale równie dobrze można wykorzystać metody set/get.