Was ist das Strategy Pattern?

Das Strategie Pattern ist ein Design Pattern für Softwareentwicklung, das zur Kategorie der verhaltensorientierten Entwurfsmuster gehört.

Das Strategy Entwurfsmuster ermöglicht Dir , eine Familie von Algorithmen zu definieren, die einzelnen Algorithmen zu kapseln und sie austauschbar zu machen. Mit diesem Muster kannst Du zur Laufzeit einen Algorithmus auswählen, ohne dem Client die Details der Algorithmusimplementierung offen zu legen.

Wie funtioniert ein Strategy Pattern?

Das Strategiemuster besteht aus drei Hauptkomponenten:

Kontext

Dies ist das Objekt, das eine Strategie benötigt, um eine bestimmte Aufgabe zu erfüllen. Der Kontext definiert eine Schnittstelle, die die Strategien implementieren müssen, damit der Kontext mit ihnen interagieren kann.

Strategie

Dies ist die Schnittstelle, die das Verhalten der Algorithmen definiert. Jede Strategie stellt eine andere Implementierung des Algorithmus dar.

Konkrete Strategien

Dies sind die verschiedenen Implementierungen der Strategie-Schnittstelle.

Wenn der Kontext eine bestimmte Aufgabe ausführen muss, delegiert er die Arbeit an ein Strategieobjekt, auf das er einen Verweis hält. Der Kontext weiß nicht, welche Strategie für die Ausführung der Aufgabe verwendet wird, und es ist ihm auch egal. Das Strategieobjekt kümmert sich um die Details des Algorithmus und gibt das Ergebnis an den Kontext zurück.

Vorteile des Strategy Pattern

Der Vorteil der Verwendung des Strategiemusters ist, dass es eine Möglichkeit bietet, die Implementierung eines Algorithmus von dem Objekt zu trennen, das ihn verwendet.

Diese Trennung ermöglicht es Dir, die Implementierung des Algorithmus zu ändern, ohne dass sich dies auf den Client-Code auswirkt, der ihn verwendet. Außerdem kannst Du so neue Algorithmen erstellen, ohne den vorhandenen Code zu ändern.

Das Strategiemuster ist ein Entwurfsmuster, das es Dir ermöglicht, eine Familie von Algorithmen zu kapseln, sie austauschbar zu machen und zur Laufzeit den geeigneten Algorithmus auszuwählen.

Dieses Software-Entwurfsmuster bietet Flexibilität, Erweiterbarkeit und Wartungsfreundlichkeit für Ihren Code, indem es die Implementierung des Algorithmus von dem Objekt trennt, das ihn verwendet.

Praxisbeispiel für das Strategy-Pattern

Nehmen wir als Beispiel ein Spiel, bei dem die Spieler zwischen verschiedenen Charakteren wählen können, von denen jeder über einzigartige Fähigkeiten verfügt. In diesem Spiel kann der Spieler während des Spiels zwischen den Charakteren wechseln, und jeder Charakter hat seinen eigenen einzigartigen Kampfstil.

Context-Klasse definieren

Um dieses Spiel mithilfe des Strategiemusters zu implementieren, würden wir zunächst eine Context-Klasse definieren, die den Spielcharakter darstellt. Die Context-Klasse würde einen Verweis auf eine Strategy-Schnittstelle enthalten, die den Kampfstil der Spielfigur definiert.

Als Nächstes würden wir konkrete Strategieklassen für jeden Kampfstil der Spielfigur erstellen. Zum Beispiel könnten wir eine SwordStrategy-Klasse für einen Charakter erstellen, der ein Schwert benutzt, eine MagicStrategy-Klasse für einen Charakter, der Magie benutzt, und eine BowStrategy-Klasse für einen Charakter, der einen Bogen benutzt.

Wenn der Spieler einen Charakter auswählt, würde das Spiel ein neues Context-Objekt erstellen und die entsprechende Strategie für diesen Charakter festlegen. Das Spiel würde dann die Methode des Context-Objekts aufrufen, die die Arbeit an das entsprechende Concrete Strategy-Objekt delegieren würde.

Wenn der Spieler beispielsweise eine Figur auswählt, die ein Schwert benutzt, würde das Spiel ein neues Context-Objekt erstellen und dessen Strategie auf SwordStrategy setzen. Wenn der Spieler angreift, würde das Spiel die Angriffsmethode des Context-Objekts aufrufen, die die Arbeit an das SwordStrategy-Objekt delegiert.

Wenn der Spieler später zu einem Charakter wechselt, der Magie verwendet, würde das Spiel ein neues Context-Objekt erstellen und dessen Strategie auf MagicStrategy setzen. Wenn der Spieler angreift, würde das Spiel die Angriffsmethode des Context-Objekts aufrufen, die die Arbeit an das MagicStrategy-Objekt delegiert.

Auf diese Weise ermöglicht es das Strategy-Muster, den einzigartigen Kampfstil eines jeden Charakters zu kapseln und sie austauschbar zu machen. Es erlaubt uns auch, neue Charaktere mit ihren eigenen Kampfstilen hinzuzufügen, ohne den bestehenden Code zu ändern.

Codebeispiel für das Strategy-Pattern in JavaScript

Hier ist eine Implementierung des Strategiemusters in JavaScript, die unsere Fantasy-Story mit Elfen, Zwergen und Magiern aus dem obigen Praxisbeispiel verwendet:

In diesem Code-Beispiel definieren wir eine FightingStrategy-Schnittstelle und erstellen konkrete Strategieklassen für die Kampfstile der einzelnen Völker: SwordStrategy für Elfen, AxeStrategy für Zwerge und MagicStrategy für Magier.

Wir definieren auch eine Charakterklasse, die ein FightingStrategy-Objekt als Parameter annimmt und die Angriffsmethode an sie delegiert.

Wir erstellen Instanzen von Charakteren mit der entsprechenden Strategie für jede Rasse und rufen dann ihre Angriffsmethode auf. Schließlich ändern wir die Strategie für den Elfencharakter und rufen seine Angriffsmethode erneut auf, um zu demonstrieren, wie wir zur Laufzeit zwischen den Strategien wechseln können.

Beachte, dass dies nur ein vereinfachtes Beispiel ist. In einem echten Spiel wäre eine deutlich komplexere Logik und zusätzliche Klassen beteiligt.

Vorteile des Strategiemusters:

Verkapselung

Das Strategiemuster kapselt Algorithmen und macht sie austauschbar, ohne den Client-Code zu beeinträchtigen, was einen sauberen und wartbaren Code fördert.

Flexibilität

Das Strategy-Muster bietet Flexibilität, da Algorithmen zur Laufzeit ausgetauscht werden können, ohne dass der Client-Code geändert werden muss.

Erweiterbarkeit

Das Strategy-Pattern erleichtert das Hinzufügen neuer Algorithmen ohne Änderung des bestehenden Codes, was die Erweiterbarkeit fördert.

Wiederverwendbarkeit

Das Strategy-Muster fördert die Wiederverwendung von Code, indem es Algorithmen in wiederverwendbare Klassen kapselt.

Testbarkeit

Mit dem Strategy-Muster lassen sich Algorithmen leicht isoliert testen, was das Testen vereinfacht und zuverlässigen Code fördert.

Wann ist ein Strategy-Muster nicht zur Nutzung geeignet?

Übertechnisierung

Das Strategiemuster kann einem System unnötige Komplexität verleihen, wenn es nur wenige feste Algorithmen gibt und die Wahrscheinlichkeit, dass weitere Algorithmen hinzugefügt werden, gering ist.

Erhöhter Speicherverbrauch

Das Strategiemuster kann die Speichernutzung erhöhen, wenn es viele Strategien gibt oder wenn Strategien häufig erstellt werden.

Leistungs-Overhead

Das Strategy-Muster kann zu einem Leistungs-Overhead führen, wenn ein erhebliches Maß an Delegation zwischen dem Kontext und den Strategien besteht.

Erhöhte Komplexität

Das Strategy-Muster kann die Komplexität erhöhen, wenn die Schnittstellen der Algorithmen nicht gut gestaltet sind, so dass es schwierig ist, die Funktionsweise der Strategien zu verstehen. Dem lässt sich aber mit gutem API-Design begegnen.

Nicht für alle Domänen geeignet

Das Strategiemuster ist nicht für alle Bereiche geeignet, insbesondere nicht für solche, die ein hohes Maß an Leistung oder Echtzeitbeschränkungen erfordern, da der Overhead des Musters die Leistung des Systems beeinträchtigen kann.