Ich habe über die gelesen OCP-Prinzip und wie man das Strategiemuster verwendet, um dies zu erreichen.
Ich wollte versuchen, dies einigen Leuten zu erklären, aber das einzige Beispiel, an das ich denken kann, ist die Verwendung verschiedener Validierungsklassen, basierend auf dem Status einer "Bestellung".
Ich habe ein paar Artikel online gelesen, aber diese beschreiben normalerweise keinen wirklichen Grund, die Strategie anzuwenden, wie das Generieren von Berichten / Rechnungen / Validierungen usw.
Gibt es Beispiele aus der Praxis, bei denen Sie der Meinung sind, dass ein Strategiemuster üblich ist?
quelle
Cipher C =null; if (file.size() <= 2048) { C = new InMemoryCipherStrategy(); } else { c= SwaptToDiskCipher (); }
CipherFactory
kann die Präsenz diejenigen verwirren, die mit dem Strategiemuster nicht vertraut sind.Wieder ein alter Beitrag, der aber immer noch bei der Suche auftaucht, also füge ich zwei weitere Beispiele hinzu (Code ist in C #). Ich liebe das Strategiemuster absolut, da es meinen Hintern oft gerettet hat, wenn die Projektmanager sagen: "Wir möchten, dass die Anwendung 'X' ausführt, aber 'X' ist noch nicht klar und kann sich in naher Zukunft ändern. "" Dieses Video erklärt das Strategiemuster , wird StarCraft als Beispiel verwendet.
Sachen, die in diese Kategorie fallen:
Sortieren: Wir möchten diese Zahlen sortieren, wissen aber nicht, ob wir BrickSort, BubbleSort oder eine andere Sortierung verwenden werden
Validierung: Wir müssen Elemente gemäß "Einige Regeln" überprüfen, aber es ist noch nicht klar, wie diese Regel aussehen wird, und wir denken möglicherweise an neue.
Spiele: Wir möchten, dass der Spieler entweder läuft oder rennt, wenn er sich bewegt, aber vielleicht sollte er in Zukunft auch schwimmen, fliegen, teleportieren, unter der Erde graben usw.
Speichern von Informationen: Wir möchten, dass die Anwendung Informationen in der Datenbank speichert, aber später muss sie möglicherweise eine Datei speichern oder einen Webcall durchführen können
Ausgabe: Wir müssen X als einfache Zeichenfolge ausgeben, später kann es sich jedoch um eine CSV, XML, JSON usw. handeln.
Beispiele
Ich habe ein Projekt, in dem die Benutzer Produkte Personen in einer Datenbank zuweisen können. Diese Zuordnung eines Produkts zu einer Person hat den Status "Genehmigt" oder "Abgelehnt", was von einigen Geschäftsregeln abhängt. Beispiel: Wenn ein Benutzer einer Person mit einem bestimmten Alter ein Produkt zuweist, sollte sein Status abgelehnt werden. Wenn der Unterschied zwischen zwei Feldern im Element größer als 50 ist, wird der Status usw. abgelehnt.
Zum Zeitpunkt der Entwicklung sind diese Geschäftsregeln noch nicht vollständig geklärt, und es können jederzeit neue Regeln entstehen. Die Stärke des Stragety-Musters besteht darin, dass ich einen RuleAgent erstellt habe, der eine Liste von IRules enthält.
Im Moment der Zuweisung eines Produkts zu einer Person erstelle ich einen RuleAgent, gebe ihm eine Liste von Regeln (die alle IRule implementieren) und fordere ihn auf, eine Zuordnung zu validieren. Es wird alle seine Regeln durchlaufen. Da alle dieselbe Schnittstelle implementieren, haben alle die
IsApproved
Methode und geben false zurück, wenn einer von ihnen false zurückgibt.Wenn jetzt zum Beispiel der Manager plötzlich auftaucht und sagt, wir müssen auch alle Aufgaben an Praktikanten oder alle Aufgaben an Überstunden ablehnen ... Sie machen neue Klassen wie diese:
Sie sehen, dass Sie keine if-Anweisungen oder Code hinzufügen oder entfernen müssen. Erstellen Sie einfach eine neue Regelklasse, die die IRUle-Schnittstelle implementiert, und schalten Sie diese bei Bedarf aus.
Ein weiteres gutes Beispiel: Scott Allens Videoserie unter http://www.asp.net/mvc/pluralsight in der er das Strategiemuster im Unit-Test-Teil der Anwendung verwendet
Er erstellt eine Website mit einer Seite, auf der Artikel nach Beliebtheit angezeigt werden. "Beliebt" kann jedoch viele Dinge sein (die meisten Ansichten, die meisten Abonnenten, das Erstellungsdatum, die meisten Aktivitäten, die geringste Anzahl von Kommentaren usw.), und falls das Management noch nicht genau weiß, wie es bestellt werden soll, und möglicherweise mit anderen experimentieren möchte Bestellungen zu einem späteren Zeitpunkt. Sie erstellen eine Schnittstelle (IOrderAlgorithm oder so) mit einer Bestellmethode und lassen ein Orderer-Objekt die Bestellung an eine konkrete Implementierung der IOrderAlgorithm-Schnittstelle delegieren. Sie können einen "CommentOrderer", "ActivityOrderer" usw. erstellen und diese einfach ausschalten, wenn neue Anforderungen auftauchen.
quelle
InternRule
jetzt, aber wie lösen wir ausOvertimeRule
? Wie stellen wir sicher, dass dieOvertimeRule.IsApproved
jetzt aufgerufene Logik auch aufgerufen wirdInternRule.IsApproved
?Wichtige Hinweise:
Strategie ist Verhaltensmuster. Es wird verwendet, um zwischen einer Familie von Algorithmen zu wechseln.
Dieses Muster enthält eine abstrakte Strategie- Schnittstelle und viele konkrete Strategie-Implementierungen ( Algorithmen ) dieser Schnittstelle.
Die Anwendung verwendet nur die Strategie- Schnittstelle . Abhängig von einigen Konfigurationsparametern wird die konkrete Strategie der Schnittstelle zugeordnet .
UML-Diagramm aus Wikipedia
Ein echtes Wortbeispiel: Fluggesellschaften, die in einigen Monaten (Juli bis Dezember) Rabatte anbieten . Sie können ein Tarifmodul verwenden , das die Preisoptionen abhängig von der Monatszahl festlegt.
Schauen Sie sich ein einfaches Beispiel an. Dieses Beispiel kann auf Online-Einzelhandelsanwendungen erweitert werden, mit denen Warenkorbartikel an bestimmten Tagen / Happy Hour problemlos rabattiert werden können.
Ausgabe:
Nützliche Artikel:
Strategiemuster von dzone
Strategiemuster durch Quellenherstellung
quelle
Ich kann mir einige ziemlich einfache Beispiele vorstellen:
Datenkompression. Möglicherweise haben Sie eine ICompressor-Schnittstelle, deren einzige Methode ungefähr so aussieht:
Byte [] komprimieren (Byte [] Eingabe);
Ihre konkreten Komprimierungsklassen können beispielsweise RunLengthCompression, DeflateCompression usw. sein.
quelle
Eine häufige Verwendung des Strategiemusters besteht darin, benutzerdefinierte Sortierstrategien (in Sprachen ohne Funktionen höherer Ordnung) zu definieren, z. B. eine Liste von Zeichenfolgen nach Länge in Java zu sortieren und dabei eine anonyme innere Klasse zu übergeben (eine Implementierung der Strategie-Schnittstelle):
In ähnlicher Weise können Strategien für native Abfragen mit Objektdatenbanken verwendet werden, z. B. in db4o:
quelle
Ich habe eine Anwendung, die ihre Benutzerbasis jeden Tag mit unserem Unternehmensverzeichnis synchronisiert. Benutzer sind aufgrund ihres Status an der Universität berechtigt oder nicht berechtigt. Jeden Tag durchläuft das Bereitstellungsprogramm und stellt sicher, dass diejenigen, die berechtigt sein sollen, in der Anwendung bereitgestellt werden und diejenigen, die nicht de-bereitgestellt werden (tatsächlich nach einem Algorithmus für eine ordnungsgemäße Verschlechterung, aber das ist nebensächlich). Am Samstag mache ich ein gründlicheres Update, das einige Eigenschaften jedes Benutzers synchronisiert und sicherstellt, dass sie die richtige Berechtigung haben. Am Ende des Monats mache ich eine Rückbuchungsverarbeitung basierend auf der Nutzung für diesen Monat.
Ich verwende ein zusammensetzbares Strategiemuster, um diese Synchronisation durchzuführen. Das Hauptprogramm wählt grundsätzlich eine Master-Strategie in Abhängigkeit vom Wochentag (nur Synchronisierungsänderungen / Alle synchronisieren) und der Semesterzeit im Verhältnis zum akademischen Kalender. Wenn der Abrechnungszyklus endet, wird er auch mit einer Abrechnungsstrategie erstellt. Anschließend wird die ausgewählte Strategie über eine Standardschnittstelle ausgeführt.
Ich weiß nicht, wie häufig dies vorkommt, aber ich hatte das Gefühl, dass es perfekt zum Strategiemuster passt.
quelle
Ich weiß, dass dies eine alte Frage ist, aber ich denke, ich habe ein weiteres interessantes Beispiel, das ich kürzlich implementiert habe.
Dies ist ein sehr praktisches Beispiel für das Strategiemuster, das in einem Dokumentenlieferungssystem verwendet wird.
Ich hatte ein PDF-Liefersystem, das ein Archiv mit vielen Dokumenten und einigen Metadaten erhielt. Basierend auf den Metadaten wurde entschieden, wo das Dokument abgelegt werden soll. sagen wir, abhängig von den Daten, konnte ich das Dokument in speichern
A
,B
oderC
Speichersysteme, oder eine Mischung der drei.Verschiedene Kunden verwendeten dieses System und hatten im Falle von Fehlern unterschiedliche Anforderungen an die Rollback- / Fehlerbehandlung: Man wollte, dass das Liefersystem beim ersten Fehler stoppt, alle bereits gelieferten Dokumente in ihren Lagern belässt, den Prozess jedoch stoppt und nichts anderes liefert ;; Ein anderer wollte, dass es
B
bei Fehlern beim Speichern zurückgesetzt wirdC
, aber alles, was bereits geliefert wurde, belässtA
. Es ist leicht vorstellbar, dass ein dritter oder vierter auch andere Bedürfnisse haben wird.Um das Problem zu lösen, habe ich eine grundlegende Übermittlungsklasse erstellt, die die Übermittlungslogik sowie Methoden zum Zurücksetzen von Daten aus allen Speichern enthält. Diese Methoden werden vom Liefersystem im Fehlerfall nicht direkt aufgerufen. Stattdessen verwendet die Klasse Dependency Injection, um eine "Rollback / Error Handling Strategy" -Klasse (basierend auf dem Kunden, der das System verwendet) zu erhalten, die im Fehlerfall aufgerufen wird und die Rollback-Methoden aufruft, wenn dies für diese Strategie geeignet ist.
Die Übermittlungsklasse selbst meldet, was in der Strategieklasse vor sich geht (welche Dokumente an welche Speicher geliefert wurden und welche Fehler aufgetreten sind), und fragt bei jedem Fehler die Strategie, ob sie fortfahren soll oder nicht. Wenn in der Strategie "stop it" angegeben ist, ruft die Klasse die "cleanUp" -Methode der Strategie auf, die anhand der zuvor gemeldeten Informationen entscheidet, welche Rollback-Methoden von der Übermittlungsklasse aufgerufen werden sollen, oder einfach nichts unternimmt.
Ich habe jetzt zwei verschiedene Strategien: eine ist die
QuitterStrategy
(die beim ersten Fehler beendet wird und nichts bereinigt) und die andere ist dieMaximizeDeliveryToAStrategy
(die so viel wie möglich versucht, den Prozess nicht abzubrechen und niemals an den Speicher gelieferte Inhalte zurückzusetzenA
, aber Rollbacks von,B
wenn die LieferungC
fehlschlägt).Nach meinem Verständnis ist dies ein Beispiel für das Strategiemuster. Wenn Sie (ja, Sie lesen) denken, dass ich falsch liege, kommentieren Sie bitte unten und lassen Sie es mich wissen. Ich bin gespannt, was eine "reine" Verwendung des Strategiemusters bedeuten würde und welche Aspekte meiner Implementierung gegen die Definition verstoßen. Ich finde es ein bisschen lustig, weil die Strategie-Oberfläche ein bisschen fett ist. Alle Beispiele, die ich bisher gesehen habe, verwenden nur eine Methode, aber ich denke immer noch, dass dies einen Algorithmus einschließt (wenn ein Teil der Geschäftslogik als Algorithmus betrachtet werden kann, was meiner Meinung nach auch so ist).
Da die Strategie auch während der Ausführungsausführung über Ereignisse informiert wird, kann sie auch als Beobachter betrachtet werden , aber das ist eine andere Geschichte.
Nach ein wenig Recherche scheint es sich um ein "zusammengesetztes Muster" zu handeln (wie MVC, ein Muster, das auf besondere Weise mehrere darunter liegende Entwurfsmuster verwendet), das als Advisor bezeichnet wird . Es ist ein Ratgeber, ob die Lieferung fortgesetzt werden soll oder nicht, aber es ist auch ein aktiver Fehlerbehandler, da es auf Anfrage Rollbacks durchführen kann.
Wie auch immer, dies ist ein ziemlich komplexes Beispiel, das Ihnen das Gefühl geben könnte, dass die Verwendung des Strategiemusters allzu einfach / albern ist. Es kann sehr komplex und noch anwendbarer sein, wenn es zusammen mit anderen Mustern verwendet wird.
quelle
Strategiemuster werden am häufigsten speziell für Validierungen und Sortieralgorithmen verwendet.
Lassen Sie mich anhand eines einfachen praktischen Beispiels erklären
Der Testcode dafür ist
Das gleiche Beispiel stammt von http://coder2design.com/strategy-pattern/
quelle
Ein gutes Beispiel für ein Strategiemuster wäre ein Spiel, in dem wir verschiedene Charaktere haben können und jeder Charakter mehrere Waffen zum Angriff haben kann, aber gleichzeitig nur eine Waffe verwenden kann. Wir haben also den Charakter als Kontext, zum Beispiel König, Kommandant, Ritter, Soldat und Waffe als Strategie, bei der attack () die Methode / der Algorithmus sein kann, die von den verwendeten Waffen abhängt. Wenn die konkreten Waffenklassen also Schwert, Axt, Armbrust, Bogen und Pfeil usw. wären, würden sie alle die attack () -Methode implementieren. Ich bin sicher, dass keine weitere Erklärung erforderlich ist.
quelle
Ich habe den Strategieansatz in einer ziemlich komplexen Engine in einer Anwendung verwendet, die ein gutes Beispiel ist. Im Wesentlichen bestand die Aufgabe der Engine darin, zunächst eine Liste der Personen zu finden, die über ein Widget verfügten. Die zweite Aufgabe bestand darin, anhand einer unbekannten Anzahl von Parametern (z. B. Preisentfernung im vorherigen Geschäft) herauszufinden, welche der 10 besten Personen mit einem Widget die besten waren , Lagerbestand, Versandoptionen usw. usw. usw. ...)
Im Wesentlichen haben wir das Problem in zwei Strategien unterteilt: Die erste war das Abrufen von Daten, da wir wussten, dass wir mehrere Quellen für unsere Widgets hatten und in der Lage sein mussten, die Daten abzurufen und in eine gemeinsame Struktur umzuwandeln.
Wir stellten dann auch fest, dass wir mehrere Algorithmen hatten, von denen einige auf der Gewichtung der Parameter beruhten, andere sehr seltsam und eigenwillig waren, und ich konnte ihnen nicht gerecht werden, ohne Visiere und Diagramme herauszuziehen, und nun, Sie haben das Bild, wir hatten viele Algorithmen für Auswahl der besten Leute.
Unser Service selbst war genau das, was er im Wesentlichen die Ein- und Ausgänge definierte und die Daten normalisierte. Außerdem verwendete er ein Anbietermuster, um die anwendungsspezifischen Datenanbieter und Algorithmusanbieter, die die Strategie verwendeten, einzubinden. Dies war ein ziemlich effektives System.
Wir hatten einige Debatten, ob wir eine Strategie oder ein Vorlagenmuster verwendeten, das wir nie gelöst haben.
quelle
Sind Sie sicher, dass der Status einer "Bestellung" kein Zustandsmuster ist? Ich habe die Vermutung, dass eine Bestellung je nach Status nicht unterschiedlich behandelt wird.
Nehmen Sie zum Beispiel die Methode Schiff auf der Bestellung:
Das beste Beispiel für das Zustandsmuster (und andere Muster), das ich gefunden habe, war das Buch " Head First Design Patterns ", das erstaunlich ist. Eine knappe Sekunde wird David Cumps 'Blogging-Reihe von Mustern sein .
quelle
Angenommen , Sie möchten einen Algorithmus schreiben, um den n-ten X-Tag eines bestimmten Monats und Jahres zu berechnen , z. B. den zweiten Montag im Oktober 2014. Sie möchten die Zeitklasse von Android verwenden
android.text.format.Time
, um das Datum darzustellen, möchten aber auch einen generischen Algorithmus schreiben das kann auch gelten fürjava.util.Calendar
.Das habe ich getan.
In DatetimeMath.java:
In TimeMath.java:
In OrdinalDayOfWeekCalculator.java die Klasse mit dem generischen Algorithmus:
In meiner Android-App würde ich so etwas wie nennen
Wenn ich denselben Algorithmus für wiederverwenden
java.util.Calendar
möchte, schreibe ich einfach eine Klasse CalendarMath, die die drei Methoden in DatetimeMath implementiert, und verwende sie dannquelle
quelle
Vor einigen Wochen habe ich eine gemeinsame Java-Schnittstelle hinzugefügt, die von einem unserer Domänenobjekte implementiert wurde. Dieses Domänenobjekt wurde aus der Datenbank geladen, und die Datenbankdarstellung war ein Sternschema mit mehr als 10 Zweigen. Eine der Konsequenzen eines so schwergewichtigen Domänenobjekts ist, dass wir andere Domänenobjekte erstellen mussten, die dasselbe Schema repräsentierten, wenn auch weniger schwergewichtig. Also habe ich die anderen leichten Objekte dazu gebracht, dieselbe Schnittstelle zu implementieren. Anders ausgedrückt hatten wir:
Ursprünglich wollte ich s
CollectibleElephant
sortierenElephant
. Ziemlich schnell kamen meine Teamkollegen dazuCollectibleElephant
, Sicherheitsüberprüfungen durchzuführen , sie zu filtern, wenn sie an die GUI gesendet werden usw.quelle
Wir mussten eine Bereitstellungsschnittstelle eines Drittanbieters für eine Unternehmensplattform mit einer sehr komplizierten Datenbank erstellen. Die Übermittlung der bereitzustellenden Daten erfolgte als Liste unserer Datentypen, die in unserer Anwendung in eine Prioritätswarteschlange gestellt wurden, damit sie aufgrund von Abhängigkeiten in der richtigen Reihenfolge in die Datenbank geschrieben werden konnten.
Das Schreiben dieser Daten war dann recht einfach. Stellen Sie sich immer wieder ganz oben in der Prioritätswarteschlange auf und wählen Sie eine Strategie aus, die auf dem Typ des zu extrahierenden Objekts basiert.
quelle
Aus Wikipedia
In der Windows Paint-Anwendung sehen Sie ein Strategiemuster, in dem Sie Form und Farbe in verschiedenen Abschnitten unabhängig voneinander auswählen können. Hier sind Form und Farbe die Algorithmen, die zur Laufzeit geändert werden können.
Wenn Sie einen Kreis mit roter Farbe zeichnen möchten, anstatt die Option 'RedCircle' bereitzustellen, können Sie den Kreis und eine Farbe Ihrer Wahl auswählen.
Ohne Strategiemuster erhöht sich die Anzahl der Klassen mit dem kartesischen Produkt aus Form und Farbe. Auch die Schnittstelle ändert sich für jede Implementierung.
quelle
Stellen Sie sich zum Beispiel ein Shooter-Spiel mit KI-Feinden vor. Sie möchten, dass sie kontinuierlich auf unterschiedliche Weise kämpfen, je nachdem, was passiert. Mit dem Strategiemuster können Sie kontinuierlich wiederholen und dynamisch ändern, wie eine bestimmte Aktion ausgeführt wird.
quelle