Napisany lis-22-2009
stan
Stan to kolejny wzorzec projektowy, z którym chciałbym Was zapoznać. W dużym stopniu wykazuje on podobieństwo do innego wzorca, którego miałem już okazję opisywać - strategii. Stan posługuje się kompozycją obiektów, implementujących ten sam interfejs, przez co pozwala na swobodne zmiany sposobu wykonania tych samych czynności w zależności od potrzeb (a konkretniej stanu obiektu). Cały proces jest poddany hermetyzacji, zatem używając klasy wykorzystującej ów wzorzec zmiany delegacji są przed nami ukrywane. Choć może się to wydawać troszkę niezrozumiałe, zapraszam do zapoznania się z poniższym przykładem.
stan w praktyce
Przyjmijmy następujące założenie. Chcemy uzależnić wywoływanie kolejnych metod na obiekcie, na podstawie typu zmiennej (integer,boolean,itp.) wcześniej do niego przekazanej. Zatem chciałbym, aby do “obsługi” integer’a,boolean’a został delegowany odpowiedni, dedykowany obiekt. Spójrzmy na poniższy przykład:
interface Stan {
public function CheckIt ($value);
public function WriteMessage ();
}
Powyżej znajduje się interfejs dla klas (ich implementacja znajduje się poniżej), które będą obsługiwać poszczególne typy zmiennych. Metoda CheckIt($value) sprawdza typ przekazanego parametru a metoda WriteMessage() wypisze go na wyjściu.
class NoStan implements Stan {
private $stan;
public function __construct (UseStan $usestan) {
$this->stan = $usestan;
}
public function CheckIt ($value) {
if (is_int($value))
$this->stan->ChangeStan($this->stan->GetIntegerStan());
elseif (is_bool($value))
$this->stan->ChangeStan($this->stan->GetBooleanStan());
elseif (is_string($value))
$this->stan->ChangeStan($this->stan->GetStringStan());
}
public function WriteMessage () {
echo 'Nie wywolano metody CheckIt()!';
}
}
class IntegerStan implements Stan {
private $stan;
public function __construct (UseStan $usestan) {
$this->stan = $usestan;
}
public function CheckIt ($value) {
echo 'Metoda CheckIt() byla juz wolana!';
}
public function WriteMessage () {
$this->stan->ChangeStan($this->stan->GetNoStan());
echo 'INTEGER';
}
}
class StringStan implements Stan {
private $stan;
public function __construct (UseStan $usestan) {
$this->stan = $usestan;
}
public function CheckIt ($value) {
echo 'Metoda CheckIt() byla juz wolana!';
}
public function WriteMessage () {
$this->stan->ChangeStan($this->stan->GetNoStan());
echo 'STRING';
}
}
class BooleanStan implements Stan {
private $stan;
public function __construct (UseStan $usestan) {
$this->stan = $usestan;
}
public function CheckIt ($value) {
echo 'Metoda CheckIt() byla juz wolana!';
}
public function WriteMessage () {
$this->stan->ChangeStan($this->stan->GetNoStan());
echo 'BOOLEAN';
}
}
Jak widać każdy typ danych ma swoją klasę (string - StringStan, itd.). Wyjątek stanowi NoStan, której zadaniem jest określenie typu zmiennej $value przekazanej w metodzie CheckIt($value),a następnie wydelegowanie do dalszej obsługi metod interfejsu Stan instancji odpowiedniej klasy(StringStan,BooleanStan,itd.). Może zastanawiać do czego służy i czym jest prywatna właściwość $stan klasy UseStan. Zatem spójrzmy na jej implementację:
class UseStan {
private $nostan;
private $integerstan;
private $stringstan;
private $booleanstan;
private $stan;
public function __construct () {
// przekazywanie w parametrze obiektu klasy UseStan ($this)
// pozwoli na swobodna zmiane delegacji przez klasy stanow
// z uzyciem setter'a stanu i getterow wszystkich stanow
$this->nostan = new Nostan($this);
$this->integerstan = new IntegerStan($this);
$this->stringstan = new StringStan($this);
$this->booleanstan = new BooleanStan($this);
// na poczatku nie wiemy jaki typ zmiennej bedzie przekazany, zatem
// inicjujemy wlasciwosc obiektem klasy NoStan
$this->stan = $this->nostan;
}
//implementacja interfejsu obiektow - stanow
public function CheckIt ($value) {
$this->stan->CheckIt($value);
}
public function WriteMessage () {
$this->stan->WriteMessage();
}
// metoda delegujaca nowy obiekt stanu do pracy
public function ChangeStan (Stan $newstan) {
$this->stan = $newstan;
}
// gettery stanów
public function GetNoStan () {
return $this->nostan;
}
public function GetIntegerStan () {
return $this->integerstan;
}
public function GetStringStan () {
return $this->stringstan;
}
public function GetBooleanStan () {
return $this->booleanstan;
}
}
Obiekty stanów używają instancji klasy UseStan która je posiada, do zmiany delegacji (stąd gettery wszystkich stanów i setter ChangeStan($nowystan)). Na koniec użycie:
$obj = new UseStan(); // W zaleznosci od typu parametru, zostanie wydelegowana instancja // odpowiednej klasy do dalszej obslugi metod interfejsu Stan. $obj->CheckIt(true); // Stad tez metoda WriteMessage wywolana zostanie na obiekcie klasy // BooleanStan a nie zadnym innym. $obj->WriteMessage();
Powyższy przykład jest prosty i ma na celu zrozumienie wzorca Stan. Mam nadzieje, iż w jakimś stopniu Wam w tym pomogłem. Kod przykładu znajduje się TUTAJ

Musze przyznać, że nie słyszałem o wzorcu Stanu, więc gratuluję ciekawego artykułu. ;]
BTW. Popraw trochę kolorowanie składni, tzn. usuń te puste linie, bo ciężko czyta się te przykłady.
Tak, muszę poprawić parę rzeczy, jak tylko znajdę chwilę wolnego czasu