State Class Pattern in PHP, finite state machine
Ich hab mal das State Class Pattern, für welches es viele Beispiele in Java gibt in PHP nachgebaut.
Als Beispiel den beliebten Kaugummiautomaten mit ganzen 3 verschiedenen Zuständen (States) und 3 Übergängen (Actions).
Zustände sind vorhanden: "NoQuarter" (Kein Geld eingeworfen), "HasQuarter" (Geld eingeworfen) und "OutOfGumballs" (Keine Kaugummis mehr vorhanden).
Übergänge sind: "insertQuarter" (Geld einwerfen), "returnQuarter" (Geld zurückgeben) und "turnCrank" (Kaugummi ziehen).
In Php sieht das dann folgendermaßen aus:
PHP:
-
<?php
-
class GumballMachine {
-
public $currentState;
-
public $numberOfGumballs=5;
-
public function refill($newGumballs) {
-
$this->numberOfGumballs=$newGumballs;
-
$this->currentState=new NoQuarter();
-
}
-
public function GumballMachine() {
-
$this->currentState=new NoQuarter();
-
$this->numberOfGumballs=5;
-
}
-
public function insertQuarter() {
-
$this->currentState->insertQuarter($this);
-
}
-
public function turnCrank() {
-
$this->currentState->turnCrank($this);
-
}
-
public function returnQuarter() {
-
$this->currentState->returnQuarter($this);
-
}
-
}
-
-
// unsere Abstrakte Zustandsklasse,
-
// da wir diese Erweitern gehen wir sicher
-
// das alle nötigen Übergänge implementiert werden.
-
abstract class GumballState {
-
public function insertQuarter($machine) {}
-
public function turnCrank($machine) {}
-
public function returnQuarter($machine) {}
-
public function __call($one, $two) {
-
echo 'Dieser Aufruf ist aus dem
-
aktuellen Zustand nicht erlaubt'."\n";
-
}
-
}
-
-
// Der State NoQuarter
-
// hier wird auf die einzelnen Übergänge reagiert
-
class NoQuarter extends GumballState {
-
public function insertQuarter(GumballMachine $machine) {
-
// Status auf HasQuarter setzen
-
$machine->currentState=new HasQuarter();
-
}
-
public function returnQuarter(GumballMachine $machine) {
-
}
-
public function turnCrank(GumballMachine $machine) {
-
}
-
public function __call($one, $two) {
-
echo 'Dieser Aufruf ist aus dem aktuellen
-
Zustand nicht erlaubt'."\n";
-
}
-
}
-
-
class HasQuarter extends GumballState {
-
public function insertQuarter(GumballMachine $machine) {
-
}
-
public function returnQuarter(GumballMachine $machine) {
-
// Status auf NoQuarter setzen
-
$machine->currentState=new NoQuarter();
-
}
-
public function turnCrank(GumballMachine $machine) {
-
if($machine->numberOfGumballs<=1)
-
$machine->currentState=new OutOfGumballs();
-
else {
-
$machine->numberOfGumballs--;
-
$machine->currentState=new NoQuarter();
-
}
-
}
-
public function __call($one, $two) {
-
echo 'Dieser Aufruf ist aus dem
-
aktuellen Zustand nicht erlaubt'."\n";
-
}
-
}
-
-
class OutOfGumballs extends GumballState {
-
public function __call($one, $two) {
-
echo 'Dieser Aufruf ist aus dem
-
aktuellen Zustand nicht erlaubt'."\n";
-
}
-
public function insertQuarter(GumballMachine $machine) {
-
}
-
public function turnCrank(GumballMachine $machine) {
-
}
-
public function returnQuarter(GumballMachine $machine) {
-
}
-
}
-
?>
-
<pre>
-
<?php
-
// Test des Kaugummi Automaten
-
$oGumballMachine=new GumballMachine();
-
$oGumballMachine->insertQuarter();
-
$oGumballMachine->turnCrank();
-
$oGumballMachine->turnCrank();
-
$oGumballMachine->insertQuarter();
-
$oGumballMachine->insertQuarter();
-
$oGumballMachine->turnCrank();
-
$oGumballMachine->returnQuarter();
-
$oGumballMachine->insertQuarter();
-
$oGumballMachine->returnQuarter();
-
$oGumballMachine->insertQuarter();
-
$oGumballMachine->turnCrank();
-
$oGumballMachine->insertQuarter();
-
$oGumballMachine->turnCrank();
-
$oGumballMachine->insertQuarter();
-
$oGumballMachine->turnCrank();
-
$oGumballMachine->insertQuarter();
-
$oGumballMachine->turnCrank();
-
$oGumballMachine->insertQuarter();
-
$oGumballMachine->turnCrank();
-
// anscheinend gibts keine Kaugummis mehr
-
// Service Techniker kommt und füllt Automat nach...
-
$oGumballMachine->insertQuarter();
-
$oGumballMachine->refill(5);
-
-
$oGumballMachine->insertQuarter();
-
$oGumballMachine->turnCrank();
-
$oGumballMachine->insertQuarter();
-
$oGumballMachine->turnCrank();
-
?></pre>