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

Tagi : ,

Komentarze:

Napisz komentarz