Wo ist der Vorteil bei der Verwendung der Strategie-Muster?
Habe ich mir angeschaut diese Erklärung auf Wikipedia, speziell die C++ - Beispiel, und erkennen nicht den Unterschied zwischen einfach nur die Definition von 3 Klassen, erzeugen von Instanzen und Aufruf von Ihnen, und das Beispiel. Was ich gesehen habe war die Platzierung nur zwei weitere Klassen in den Prozess und kann nicht sehen, wo es wäre ein Vorteil. Jetzt bin ich sicher, ich bin etwas fehlt offensichtlich (Holz für die Bäume) - könnte jemand bitte erklären Sie es mithilfe eines endgültigen real-world-Beispiel?
Was kann ich aus den Antworten so weit, es scheint mir nur eine komplexere Art und Weise, dies zu tun:
have an abstract class: MoveAlong with a virtual method: DoIt()
have class Car inherit from MoveAlong,
implementing DoIt() { ..start-car-and-drive..}
have class HorseCart inherit from MoveAlong,
implementing DoIt() { ..hit-horse..}
have class Bicycle inherit from MoveAlong,
implementing DoIt() { ..pedal..}
now I can call any function taking MoveAlong as parm
passing any of the three classes and call DoIt
Isn't this what Strategy intents? (just simpler?)
[Edit-update]
Die Funktion Verweise ich auf oben ist ersetzt mit einer anderen Klasse, in der MoveAlong wäre Attribut, das gesetzt wird, je nach Bedarf basierend auf den implementierten Algorithmus in dieser neuen Klasse. (Ähnlich zu dem, was nachgewiesen ist, in der akzeptierten Antwort.)
[Edit-update] Abschluss
Dem Strategie-Muster hat es verwendet, aber ich bin ein starker Gläubiger in KISS, und würde dazu neigen, einfacher und weniger obfuscatory Techniken. Meist da möchte ich weitergeben leicht wartbaren code (und 'cos ich werde wahrscheinlich derjenige sein, der die änderungen!).
- "Ist das nicht das, was Strategie-Absichten? (nur einfacher?)" <-- ziemlich viel, außer, dass Sie geben eine Referenz auf Ihre Klasse und lassen Sie die andere Klasse aufrufen, wenn es muss, während die anderen in der Klasse nur weiß, dass es eine MoveAlong. Es ist eines dieser Dinge, das ist mehr nützlich, in einer team situation.
- Hallo gerald ich denke, Ihr Beispiel ist ein schlechtes Beispiel für Strategie-Muster. ja, es ist eine Strategie, die aber in deinem Fall wäre es besser zu haben als Unterklassen implementieren Strategie-Muster. Im ziemlich sicher, dass martian Uhr hätte anders Verhalten, als die Erde Uhr, daher lohnt es Unterklassen die Uhr Klasse.
- lol... ich sah gerade diesen Kommentar. Ich nehme an, wenn Sie erwarten, dass die clients auf dem Mars, dass es sich lohnen könnte, sich Gedanken über eine mars-Uhr in Ihre Entwürfe. Aber da 100% der meisten Völker Klienten gehen zu den Menschen auf der Erde, mit einem universal-Zeit-Darstellung der Daten, ich denke es ist ziemlich sicher zu ignorieren, dass die edge-Fall, es sei denn, es ist für ein video-Spiel.
- Aber Strategie-Muster ist Recht einfach, auch wenn Sie nur den code zu verwalten
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ist der Punkt, um eigene algorithmen in Klassen, die angeschlossen werden können zur Laufzeit. Zum Beispiel, sagen wir, Sie haben eine Anwendung, die enthält eine Uhr. Es gibt viele verschiedene Möglichkeiten, Sie können zeichnen Sie eine Uhr, aber für den größten Teil der zugrunde liegenden Funktionalität ist die gleiche. So können Sie eine Uhr-Anzeige-Schnittstelle:
Dann haben Sie Ihre Uhr Klasse, angeschlossen an einen timer und aktualisiert die Uhrzeit-Anzeige einmal pro Sekunde. So würden Sie etwas wie:
Dann bei Laufzeit, die Sie instanziieren Sie Ihre Uhr mit der richtigen Anzeige Klasse. d.h. Sie hätte ClockDisplayDigital, ClockDisplayAnalog, ClockDisplayMartian alle der Umsetzung der IClockDisplay-Schnittstelle.
So können Sie später hinzufügen, jede Art von neuen Uhrzeit-Anzeige eine neue Klasse zu erstellen, ohne zu verwirren mit Ihrer Uhr Klasse, und die zimmerreserviereung, ohne das überschreiben von Methoden, chaotisch zu pflegen und zu Debuggen.
In Java verwenden Sie eine Chiffre-input-stream zu entschlüsseln, wie also:
Aber die cipher-stream hat keine Kenntnis von dem, was Verschlüsselungs-Algorithmus, den Sie verwenden möchten, oder die block-Größe, Polsterung Strategie, etc... Neue algorithmen Hinzugefügt werden die ganze Zeit so hardcoding ist nicht praktisch. Stattdessen passieren wir in eine Chiffre Strategie-Objekt zu erzählen, wie die Entschlüsselung...
Im Allgemeinen verwenden Sie das Strategie-Muster Sie haben jederzeit ein beliebiges Objekt, das weiß, dass was es tun muss, aber nicht wie, es zu tun. Ein weiteres gutes Beispiel ist die layout-Manager in Swing, obwohl in diesem Fall es nicht ganz so gut, siehe Totally GridBag für eine amüsante illustration.
NB: Es gibt zwei Muster, die hier am Werke, wie die Verpackung von Bächen in den Bächen ist ein Beispiel von Dekorateur.
Es gibt einen Unterschied zwischen Strategie und Entscheidung/Wahl. Die meisten der Zeit, ein we wäre Umgang mit Entscheidungen/Entscheidungen in unserem code, und setzen Sie mit wenn()/switch () - Konstrukte. Strategie-Muster ist nützlich, wenn es notwendig ist, zu entkoppeln der Logik/Algorithmus aus der Nutzung.
Als ein Beispiel, Denken Sie an einen polling-Mechanismus, bei denen unterschiedliche Benutzer zu überprüfen wäre für Ressourcen/updates. Nun wollen wir einige der priveliged Benutzer benachrichtigt werden, um eine schnellere Durchlaufzeit oder mit mehr details. Essentailly die Logik, die verwendet wird, änderungen, basierend auf Benutzer-Rollen. Strategie Sinn macht, von einem design - /Architektur-Sicht auf den unteren Ebenen der Granularität es sollte immer hinterfragt werden.
Dem Strategie-Muster können Sie nutzen polimorphism ohne erweitern Sie Ihre main-Klasse. Im wesentlichen, Sie setzen alle Variablen Teile in die Strategie von interface und Implementierung und die main-Klasse Delegierte zu Ihnen. Wenn Ihr Haupt-Objekt verwendet nur eine Strategie, es ist fast das gleiche wie mit einer abstrakten (rein virtuellen) Methode und verschiedene Implementierungen in jeder Unterklasse.
Den Strategie-Ansatz bietet einige Vorteile:
Der Nachteil ist, dass in vielen Fällen die Strategie-Muster ist ein overkill - die "switch/case" - operator gibt es für einen Grund. Betrachten Sie mit einfachen control-flow-statements (switch/case oder if), dann nur, wenn nötig zu bewegen, um Klassen-Hierarchie und wenn Sie mehr als eine Dimensionen der Variabilität, Extrakt-Strategien aus ihm heraus. Funktion Zeiger irgendwo in der Mitte dieses Kontinuums.
Empfohlene Lektüre:
Einen Weg, dies zu betrachten ist, wenn Sie haben eine Vielzahl von Aktionen, die Sie ausführen möchten, und diese Aktionen werden zur Laufzeit ermittelt. Wenn Sie erstellen eine hashtable oder ein dictionary von Strategien, Sie könnten abgerufen werden diese Strategien entsprechen, um Sollwerte oder Parameter. Sobald Ihr Teilmenge ausgewählt ist, können Sie einfach nur Durchlaufen der Liste von Strategien und führen in Folge.
Konkreten Beispiel wäre die Berechnung der Summe der Bestellung. Ihre Parameter oder Befehle wäre Grundpreis, Kurtaxe, city tax, state tax, Boden Versand und Gutschein-Rabatt. Die Flexibilität ins Spiel kommen, wenn Sie mit der variation der Bestellungen - einige Staaten haben die Umsatzsteuer, während andere Aufträge anwenden müssen, einen Gutschein. Sie können dynamisch zuweisen die Reihenfolge der Berechnungen. Solange Sie machten alle Ihre Berechnungen können Sie für alle Kombinationen ohne re-kompilieren.
Dieses Entwurfsmuster ermöglicht Kapseln algorithmen in den Klassen.
Die Klasse, die verwendet die Strategie, die client-Klasse, ist entkoppelt von der Algorithmus-Implementierung. Sie können ändern die algorithmen, die Implementierung, oder fügen Sie neue Algorithmus ohne änderung der client. Dies kann auch getan werden, dynamisch: der client kann den Algorithmus auswählen, der er verwendet wird.
Ein Beispiel vorstellen, eine Anwendung, speichern Sie ein Bild zu einer Datei ; das Bild kann gespeichert werden in verschiedenen Formaten (PNG, JPG ...). Die Codierung der algorithmen, all das wird umgesetzt in verschiedene Klassen teilen die gleiche Schnittstelle. Die client-Klasse wählen, je nach der Vorliebe des Benutzers.
Im Wikipedia-Beispiel, diese Instanzen übergeben werden kann, in einer Funktion, die nicht darauf achten, welche Klasse diese Instanzen gehören. Die Funktion ruft einfach
execute
auf das Objekt übergeben, und wissen, dass das Richtige passieren wird.Ein typisches Beispiel für die Strategie-Muster ist, wie Dateien in Unix. Gegeben einen Datei-Deskriptor, können Sie Lesen, schreiben, Umfrage ist es, zu suchen, auf Sie, senden Sie
ioctl
s usw., ohne zu wissen, ob Sie ' re Umgang mit einem Datei -, Verzeichnis -, pipe, socket, Gerät, etc. (Natürlich sind einige Operationen, wie suchen, arbeiten nicht auf pipes und sockets. Aber liest und schreibt, wird gut funktionieren in diesen Fällen.)Das bedeutet, dass Sie generischen code schreiben, der mit all diesen verschiedenen Arten von "Dateien", ohne zu schreiben, separaten code-Umgang mit Dateien oder Verzeichnissen, etc.. Der Unix-kernel kümmert sich um die übertragung der Anrufe zu den richtigen code.
Nun ist das Strategie-Muster, wie Sie in der kernel-code, aber Sie nicht angegeben hatte, dass Sie zu Benutzer-code, nur eine Reale Welt Beispiel. 🙂
Strategie-Muster funktioniert auf eine einfache Idee, d.h. "Favor Composition over Inheritance", so dass die Strategie/Algorithmus kann zur Laufzeit geändert werden. Um zu veranschaulichen, nehmen wir ein Beispiel, wo wir verschlüsseln müssen verschiedene Nachrichten basierend auf Ihrem Typ, z.B. MailMessage, ChatMessage etc.
Nun zur Laufzeit, die Sie instanziieren können verschiedene Nachrichten geerbt von CMessage (wie CMailMessage:öffentliche CMessage) mit verschiedenen Verschlüsseler (wie CDESEncryptor:öffentliche CEncryptor)