Wzorzec Stan umożliwia zmianę zachowania obiektu, kiedy zmianie ulegnie jego wewnętrzny stan. Wzorzec ten jest bardzo użyteczny i występuje praktycznie wszędzie. Przykładem z życia może być np: przełącznik światła, który posiada dwa stany: włączony (ON) i wyłączony (OFF).
Dla przykładu zbudujemy taki minimalistyczny przełącznik 🙂
Pierwsza klasa stanu – State, jest abstrakcyjna i posiada również abstrakcyjną metodę change, która będzie zmieniać aktualny stan na inny (ale to dopiero w implementacji 😉 ). Metoda ta, poprzez typowanie przyjmuje instancję klasy Context.
1 2 3 4 5 6 7 |
<?php // State.php abstract class State { abstract public function change(Context $context); } ?> |
Klasa Context – jest najważniejsza i pozwala na bieżąco śledzić stan obiektu:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<?php // Context.php class Context { private $state; public function __construct(State $object) { $this->state = $object; } public function setState($state) { $this->state = $state; } public function getState() { return $this->state; } public function Run() { $this->state->change($this); } } ?> |
Konstruktor pobiera obiekt stanu: State $object. Metoda setState ustawia aktualny stan obiektu, a getState zwraca go. Metoda Run – to tzw. „wyzwalacz” i zmienia stan (za pomocą metody change) z aktualnego na inny. W poniższych klasach „stanu” (On / Off) będzie to widoczne.
Klasa On:
1 2 3 4 5 6 7 8 9 10 11 |
<?php // On.php class On extends State { public function change(Context $context) { echo '<p> ON </p>'; $context->setState(new Off()); } } ?> |
Klasa Off:
1 2 3 4 5 6 7 8 9 10 11 |
<?php // Off.php class Off extends State { public function change(Context $context) { echo '<p> OFF </p>'; $context->setState(new On()); } } ?> |
Obie klasy zmieniają kontekst, ustawiając (w pamięci) przeciwne stany po wykonaniu operacji ON lub OFF:
1 2 3 4 5 6 7 |
echo '<p> ON </p>'; // włączone ON $context->setState(new Off()); // ustawia OFF // analogicznie dla OFF: echo '<p> OFF </p>'; $context->setState(new On()); |
Potrzebujemy jeszcze klasy klienta (Client), której użyjemy do zabawy przełącznikiem:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?php // Client.php spl_autoload_register(function ($class_name) { include $class_name . '.php'; }); $state = new Off(); // domyślnie: OFF $context = new Context($state); // aktualny stan: OFF // "zabawa" przełącznikiem :) : $context->Run(); // OFF $context->Run(); // ON $context->Run(); // OFF $context->Run(); // ON // ... ?> |