Das Strategy Design Pattern

Einführung

Das Strategy Design Pattern hat die Aufgabe Strategien zu kapseln und austauschbar zu machen.
In unserem praktischen Beispiel möchte ich das mit Hilfe eines Grtengrundstückes darstellen. Der Besitzer des Gartengrundstückes besitzt einen Hund. Diesem Hund wurden verschiedene Strategien beigebracht.

Diese Strategien des Hundes sind im einzelnen:

  • nähert sich eine Katze dem Gartenzaun, so hat er ( der Hund ) verhalten zu bellen
  • betritt eine Katze den Garten so hat der Hund deutlich zu bellen
  • erreicht diese Katze das Gartenhaus so hat der Hund laut zu bellen und die Zähne zu fletchen

Da der Besitzer des Hundes sich nicht im klaren ist ob das Verhalten des Hundes korrekt ist,
möchte er die oben genannten Strategien ändern und gegebenenfalls durch weitere Strategien ergänzen.

Bilden wir unseren Hundes in einer Klasse ab. Dazu erstellen wir die Klasse 'hund' und erweitern diese Klasse durch 'ModelData'. Dadurch erstellen wir ein Standardmodel des Framework Frink2.

Die Skripte der Model finden sie im Framework Frink2.

Als erstes erstellen wir das Basismodel 'hund'.

Klasse Hund

class hund extends \models\ModelData
{

    public function reaktion()
    {
        if($this->data['abstandZumGartenzaun'] == 0)
            $this->data['reaktionHund'] = $this->pimple['knurrenderHund']->bellen();
        elseif( ($this->data['abstandZumGartenzaun'] > 0) and ($this->data['abstandZumGartenzaun'] < 10) )
            $this->data['reaktionHund'] = $this->pimple['bellenderHund']->bellen();
        else
            $this->data['reaktionHund'] = $this->pimple['randalierenderHund']->bellen();
    }

}

Das verhalten des Hundes kapseln wir in einzelnen Klassen. Diese Klasse haben eine einheitliche Schnittstelle 'bellen()'. Durch das Interface 'interfaceHundBellen' wird in den Strategieklassen das einheitliche Interface garantiert.

Interface interfaceHundBellen

interface interfaceHundBellen
{
    public function bellen();
}

Die einzelnen Strategien des Hundes werden in Strategie - Klassen gespeichert.

Strategie Klassen

class knurrenderHund implements \models\interfaceHundBellen
{
    public function bellen()
    {
        return 'Hund knurrt';
    }
}

class bellenderHund implements \models\interfaceHundBellen
{
    public function bellen()
    {
        return 'Hund bellt';
    }
}

class randalierenderHund implements \models\interfaceHundBellen
{
    public function bellen()
    {
        return 'Hund bellt und fletcht die Zähne';
    }
}

Unser Strategie Pattern in der praktischen Anwendung:

Im '__construct()' des Controller übergeben wir die Model an den DI Container Pimple.
Dadurch werden die Model / Strategie Model in allen Klassen verfügbar.

 public function __construct($controllerName, $actionName)
{
    // Vorbereitung des Pimple Container, Singleton Pattern !
    $models = [
        'hund' => function ($pimple) {
            return new \models\hund($pimple);
        },
        'knurrenderHund' => function ($pimple){
            return new \models\knurrenderHund();
        },
        'bellenderHund' => function ($pimple){
            return new \models\bellenderHund();
        },
        'randalierenderHund' => function ($pimple){
            return new \models\randalierenderHund();
        }
    ];

    parent::pimple($models);
}

Im Controller existiert eine Action mit dem Namen 'strategyPattern()'.
In dieser Action wird die Strategie des Hundes in Abhängigkeit des Abstand
der Katze vom Gartenzaun geändert.
Und letztendlich wird das Templat mit 'templat()' angezeigt.

public function strategyPattern()
{
    try {

        /** @var $modelHund \models\hund */
        $modelHund = $this->pimple['hund'];

        // Katze ist am Gartenzaun
        $modelHund['abstandZumGartenzaun'] = 0;
        $modelHund->reaktion();
        $reaktion = $modelHund['reaktionHund'];

        // Katze ist im Garten
        $modelHund['abstandZumGartenzaun'] = 5;
        $modelHund->reaktion();
        $reaktion = $modelHund['reaktionHund'];

        // Katze ist am Gartenhaus
        $modelHund['abstandZumGartenzaun'] = 11;
        $modelHund->reaktion();
        $reaktion = $modelHund['reaktionHund'];

        $this->template();
    }
        // eigene Exception
    catch (\tools\frinkError $e) {
        throw $e;
    } // Exception anderer Klassen
    catch (\Exception $e) {
        throw $e;
    }
}