web-dev-qa-db-de.com

Beispiel aus der realen Welt des Strategiemusters

Ich habe über den OCP-Prinzip gelesen und wie man das Strategiemuster verwendet, um dies zu erreichen.

Ich wollte versuchen, dies einigen Leuten zu erklären, aber das einzige Beispiel, das mir einfällt, ist die Verwendung verschiedener Validierungsklassen, je nachdem, welchen Status eine "Bestellung" hat.

Ich habe ein paar Artikel online gelesen, aber diese beschreiben normalerweise keinen echten Grund für die Verwendung der Strategie, wie das Erstellen von Berichten/Rechnungen/Validierungen usw.

Gibt es Beispiele aus der realen Welt, in denen Sie der Meinung sind, dass ein Strategiemuster üblich ist?

81
Tired

Was ist mit diesem: 

Sie müssen eine Datei verschlüsseln. 

Für kleine Dateien können Sie die Strategie "im Speicher" verwenden, bei der die gesamte Datei gelesen und im Speicher gehalten wird (beispielsweise bei Dateien <1 GB). 

Bei großen Dateien können Sie eine andere Strategie verwenden, bei der Teile der Datei in den Speicher gelesen und teilweise verschlüsselte Ergebnisse in tmp-Dateien gespeichert werden.

Dies können zwei unterschiedliche Strategien für dieselbe Aufgabe sein.

Der Client-Code würde gleich aussehen:

 File file = getFile();
 Cipher c = CipherFactory.getCipher( file.size() );
 c.performAction();



// implementations:
interface  Cipher  {
     public void performAction();
}

class InMemoryCipherStrategy implements Cipher { 
         public void performAction() {
             // load in byte[] ....
         }
}

class SwaptToDiskCipher implements Cipher { 
         public void performAction() {
             // swapt partial results to file.
         }

}

Das 

     Cipher c = CipherFactory.getCipher( file.size() );

Gibt die korrekte Strategieinstanz für die Chiffre zurück.

Ich hoffe das hilft.

(Ich weiß nicht mal, ob Cipher das richtige Wort ist: P)

87
OscarRyz

Wiederum taucht ein alter Beitrag immer noch bei Suchanfragen auf, also werde ich zwei weitere Beispiele hinzufügen (Code steht in C #). Ich liebe das Strategiemuster absolut, da es meinen Hintern viele Male gerettet hat, wenn die Projektmanager sagen: "Wir möchten, dass die Anwendung 'X' macht, aber 'X' ist noch nicht klar und kann sich in naher Zukunft ändern. " Dieses Video zur Erläuterung des Strategiemusters verwendet StarCraft als Beispiel.

Sachen, die in diese Kategorie fallen:

  • Sortierung: Wir möchten diese Zahlen sortieren, wissen aber nicht, ob wir BrickSort, BubbleSort oder eine andere Sortierung verwenden

  • Validierung: Wir müssen Elemente nach "Einige Regeln" prüfen, aber es ist noch nicht klar, was diese Regel sein wird, und wir können an neue denken.

  • Spiele: Wir möchten, dass der Spieler entweder läuft oder rennt, wenn er sich bewegt, aber in der Zukunft sollte er vielleicht auch schwimmen, fliegen, teleportieren, sich unterirdisch vergraben usw.

  • Speichern von Informationen: Wir möchten, dass die Anwendung Informationen in der Datenbank speichert, später muss sie jedoch möglicherweise eine Datei speichern oder einen Webcall durchführen

  • Ausgabe: Wir müssen X als einfachen String ausgeben. Später können CSV, XML, JSON usw. verwendet werden.


Beispiele

Ich habe ein Projekt, bei dem Benutzer Benutzern in einer Datenbank Produkte zuweisen können. Diese Zuordnung eines Produkts zu einer Person hat den Status "Genehmigt" oder "Abgelehnt", was von einigen Geschäftsregeln abhängig ist. Zum Beispiel: Wenn ein Benutzer einer Person mit einem bestimmten Alter ein Produkt zuweist, sollte dessen Status abgelehnt werden. Wenn der Unterschied zwischen zwei Feldern im Element größer als 50 ist, wird der Status abgelehnt usw.

Zum Zeitpunkt der Entwicklung sind diese Geschäftsregeln noch nicht vollständig klar, und es können jederzeit neue Regeln aufgestellt werden. Die Stärke des Stragety-Patterns ist, dass ich einen RuleAgent erstellt habe, der eine Liste von IRules enthält. 

public interface IRule {
    bool IsApproved(Assignment assignment); 
 }

Beim Zuweisen eines Produkts zu einer Person erstelle ich einen RuleAgent, gebe eine Liste mit Regeln (die alle IRule implementieren) ein und fordere sie auf, eine Zuweisung zu bestätigen. Es wird alle Regeln durchlaufen. Da alle dasselbe Interface implementieren, verfügen alle über die IsApproved-Methode und geben false zurück, wenn einer von ihnen false zurückgibt.

Wenn nun zum Beispiel der Manager plötzlich auftaucht und sagt, müssen wir auch alle Zuweisungen an Praktikanten oder alle Zuweisungen an Überstunden ablehnen ... Sie machen neue Klassen wie folgt:

public OvertimeRule : IRule
{
    public bool IsApproved(Assignment assignment) //Interface method
    {
        if (assignment.Person.Timesheet >= 40)
        {
            return false;
        }
        return true;
    }
}

public InternRule : IRule
{
    public bool IsApproved(Assignment assignment) //Interface method
    {
        if (assignment.Person.Title == "Intern")
        {
            return false;
        }
        return true;
    }
}

Sie sehen, dass Sie nicht ständig If-Anweisungen oder Code hinzufügen oder entfernen müssen. Erstellen Sie einfach eine neue Regelklasse, die die IRUle-Schnittstelle implementiert, und wechseln Sie diese bei Bedarf aus. 


Ein weiteres gutes Beispiel: Scott Allens Videoserie unter http://www.asp.net/mvc/pluralsight , bei der er das Strategiemuster im Unit-Test-Teil der Anwendung verwendet

Er baut eine Website mit einer Seite, auf der Artikel nach Beliebtheit angezeigt werden. "Beliebt" kann jedoch viele Dinge umfassen (die meisten Ansichten, die meisten Abonnenten, das Erstellungsdatum, die meisten Aktivitäten, die geringste Anzahl an 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 etwas anderes) mit einer Bestellmethode und lassen ein Orderer-Objekt die Bestellung an eine konkrete Implementierung der IOrderAlgorithm-Schnittstelle delegieren. Sie können einen "CommentOrderer", einen "ActivityOrderer" usw. erstellen ... und diese einfach ausschalten, wenn neue Anforderungen auftreten.

48
Céryl Wiltink

Ich kann mir einige recht einfache Beispiele vorstellen:

  • Liste sortieren Die Strategie ist der Vergleich, der verwendet wird, um zu entscheiden, welcher von zwei Elementen in der Liste "First" ist.
  • Möglicherweise haben Sie eine Anwendung, bei der der Sortieralgorithmus (QuickSort, HeapSort usw.) zur Laufzeit ausgewählt werden kann
  • Appenders, Layouts und Filter in Log4Net und Log4j
  • Layout Manager in UI-Toolkits
  • Datenkompression. Möglicherweise haben Sie eine ICompressor-Schnittstelle, deren einzige Methode in etwa wie folgt aussieht:

    byte [] Komprimieren (Byte [] Eingabe);

    Ihre konkreten Kompressionsklassen könnten Dinge wie RunLengthCompression, DeflateCompression usw. sein.

11
Eric Pohl

Das Strategiemuster wird häufig verwendet, um benutzerdefinierte Sortierstrategien (in Sprachen ohne Funktionen höherer Ordnung) zu definieren, z. So sortieren Sie eine Liste von Zeichenfolgen nach Länge in Java, wobei eine anonyme innere Klasse übergeben wird (Implementierung der Strategieschnittstelle):

List<String> names = Arrays.asList("Anne", "Joe", "Harry");
Collections.sort(names, new Comparator<String>() {
  public int compare(String o1, String o2) {
    return o1.length() - o2.length();
  }
});
Assert.assertEquals(Arrays.asList("Joe", "Anne", "Harry"), names);

In ähnlicher Weise können Strategien für native Abfragen mit Objektdatenbanken verwendet werden, z. in db4o:

List<Document> set = db.query(new Predicate<Document>() {
  public boolean match(Document candidate) {
    return candidate.getSource().contains(source);
  }
});
9
Fabian Steeg

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 als berechtigt gelten sollen, in der Anwendung bereitgestellt werden und diejenigen, die nicht zur Verfügung gestellt werden, tatsächlich (gemäß einem anmutigen Degradationsalgorithmus, was aber nicht so wichtig ist). Am Samstag führe ich ein gründlicheres Update durch, das einige Eigenschaften jedes Benutzers synchronisiert und sicherstellt, dass er die richtige Berechtigung hat. Am Ende des Monats führe ich eine Rechnungsrückerstattung nach Verbrauch für diesen Monat durch.

Ich verwende ein zusammensetzbares Strategiemuster, um diese Synchronisierung durchzuführen. Das Hauptprogramm wählt im Wesentlichen eine Master-Strategie in Abhängigkeit vom Wochentag (nur Synchronisationsänderungen/Alle synchronisieren) und der Semesterzeit relativ zum akademischen Kalender. Wenn der Abrechnungszyklus endet, wird er auch mit einer Abrechnungsstrategie erstellt. Die ausgewählte Strategie wird dann über eine Standardschnittstelle ausgeführt.

Ich weiß nicht, wie üblich dies ist, aber ich hatte das Gefühl, es passte perfekt zum Strategiemuster.

8
tvanfosson

Wichtige Anmerkungen:

  1. Strategie ist ein Verhaltensmuster. Es wird verwendet, um zwischen den Algorithmen zu wechseln. 

  2. Dieses Muster enthält eine abstrakte Strategie Schnittstelle und viele konkrete Strategieimplementierungen (Algorithmen) dieser Schnittstelle. 

  3. Die Anwendung verwendet nur die Strategie Schnittstelle. Abhängig von einigen Konfigurationsparametern wird konkrete Strategie mit Schnittstelle gekennzeichnet.

UML-Diagramm aus wikipedia

 enter image description here

Ein echtes Word-Beispiel: Fluggesellschaften, die in einigen Monaten (Juli-Dezember) Rabatte anbieten). Sie können ein Fare -Modul haben, das die Preisoptionen abhängig von der Monatsnummer bestimmt. 

Schauen Sie sich ein einfaches Beispiel an. Dieses Beispiel kann auf Online-Einzelhandelsanwendungen erweitert werden, die an besonderen Tagen/Happy-Hour-Artikeln leicht Rabatt für Einkaufswagen-Artikel bieten. 

import Java.util.*;

/* Interface for Strategy */
interface OfferStrategy {
    public String getName();
    public double getDiscountPercentage();
}
/* Concrete implementation of base Strategy */
class NoDiscountStrategy implements OfferStrategy{
    public String getName(){
        return this.getClass().getName();
    }
    public double getDiscountPercentage(){
        return 0;
    }
}
/* Concrete implementation of base Strategy */
class QuarterDiscountStrategy implements OfferStrategy{
    public String getName(){
        return this.getClass().getName();
    }
    public double getDiscountPercentage(){
        return 0.25;
    }
}
/* Context is optional. But if it is present, it acts as single point of contact
   for client. 

   Multiple uses of Context
   1. It can populate data to execute an operation of strategy
   2. It can take independent decision on Strategy creation. 
   3. In absence of Context, client should be aware of concrete strategies. Context acts a wrapper and hides internals
   4. Code re-factoring will become easy
*/
class StrategyContext {
    double price; // price for some item or air ticket etc.
    Map<String,OfferStrategy> strategyContext = new HashMap<String,OfferStrategy>();
    StrategyContext(double price){
        this.price= price;
        strategyContext.put(NoDiscountStrategy.class.getName(),new NoDiscountStrategy());
        strategyContext.put(QuarterDiscountStrategy.class.getName(),new QuarterDiscountStrategy());        
    }
    public void applyStrategy(OfferStrategy strategy){
        /* 
        Currently applyStrategy has simple implementation. You can use Context for populating some more information,
        which is required to call a particular operation            
        */
        System.out.println("Price before offer :"+price);
        double finalPrice = price - (price*strategy.getDiscountPercentage());
        System.out.println("Price after offer:"+finalPrice);
    }
    public OfferStrategy getStrategy(int monthNo){
        /*
            In absence of this Context method, client has to import relevant concrete Strategies everywhere.
            Context acts as single point of contact for the Client to get relevant Strategy
        */
        if ( monthNo < 6 )  {
            return strategyContext.get(NoDiscountStrategy.class.getName());
        }else{
            return strategyContext.get(QuarterDiscountStrategy.class.getName());
        }

    }
}
public class StrategyDemo{    
    public static void main(String args[]){
        StrategyContext context = new StrategyContext(100);
        System.out.println("Enter month number between 1 and 12");
        int month = Integer.parseInt(args[0]);
        System.out.println("Month ="+month);
        OfferStrategy strategy = context.getStrategy(month);
        context.applyStrategy(strategy);
    }

}

ausgabe:

Enter month number between 1 and 12
Month =1
Price before offer :100.0
Price after offer:100.0

Enter month number between 1 and 12
Month =7
Price before offer :100.0
Price after offer:75.0

Nützliche Artikel:

Strategie Muster von dzone

Strategie Muster durch Sourcing

8
Ravindra babu

Ich weiß, dass dies eine alte Frage ist, aber ich glaube, 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 Dokumentenliefersystem verwendet wird.

Ich hatte ein Liefersystem PDF, das ein Archiv mit vielen Dokumenten und einigen Metadaten erhielt. Basierend auf den Metadaten entschied sie, wo das Dokument eingefügt werden sollte. In Abhängigkeit von den Daten könnte ich das Dokument in A-, B- oder C-Speichersystemen oder in einer Kombination der drei speichern.

Verschiedene Kunden nutzten dieses System und hatten im Fehlerfall unterschiedliche Anforderungen an das Rollback/Error-Handling: Man wollte, dass das Liefersystem bei dem ersten Fehler stoppt, alle Dokumente bereits in ihren Lagern belässt, den Prozess jedoch anhält und nichts anderes liefert ; ein anderer wollte, dass es von B zurückkehrt, falls Fehler beim Speichern in C auftreten, aber alles, was bereits an A geliefert wurde, bleibt bestehen. 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 Bereitstellungsklasse erstellt, die die Bereitstellungslogik 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 die Abhängigkeitsinjektion, um eine Klasse "Rollback/Fehlerbehandlungsstrategie" zu erhalten (basierend auf dem Kunden, der das System verwendet), der im Fehlerfall aufgerufen wird. Diese ruft dann die Rollback-Methoden auf, sofern dies für diese Strategie geeignet ist.

Die Auslieferungsklasse selbst meldet, was der Strategieklasse passiert (welche Dokumente wurden an welche Speicher geliefert und welche Fehler aufgetreten sind). Wenn ein Fehler auftritt, werden Sie gefragt, ob Sie fortfahren möchten oder nicht. Wenn die Strategie "stop it" sagt, ruft die Klasse die "cleanUp" -Methode der Strategie auf, die die zuvor gemeldeten Informationen verwendet, um zu entscheiden, welche Rollback-Methoden von der Bereitstellungsklasse aufgerufen werden, oder einfach nichts zu tun.

rollbackStrategy.reportSuccessA(...);
rollbackStrategy.reportFailureB(...);

if (rollbackStrategy.mustAbort()) {
    rollbackStrategy.rollback(); // rollback whatever is needed based on reports
    return false;
}

Ich habe also zwei verschiedene Strategien: Eine ist die QuitterStrategy (die beim ersten Fehler aufhört und nichts aufräumt) und die andere ist die MaximizeDeliveryToAStrategy (die so viel wie möglich versucht, den Prozess nicht abzubrechen und niemals das im Speicher gelieferte Material zu rollen A, aber Rollbacks von B, falls die Zustellung an C 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" Anwendung des Strategiemusters bedeuten würde und welche Aspekte meiner Implementierung gegen die Definition verstoßen. Ich finde, es sieht ein bisschen komisch aus, weil die Strategieoberfläche etwas fett ist. Alle Beispiele, die ich bisher gesehen habe, verwenden nur eine Methode, aber ich denke immer noch, dass dies einen Algorithmus einkapselt (wenn ein Teil der Geschäftslogik als ein Algorithmus betrachtet werden kann, was meiner Meinung nach der Fall ist).

Da die Strategie auch während der Lieferungsausführung über Ereignisse informiert wird, kann sie auch als Observer betrachtet werden. Dies ist jedoch eine andere Geschichte.

Nach ein wenig Recherche scheint es sich um ein "zusammengesetztes Muster" zu handeln (wie MVC, ein Muster, das mehrere Entwurfsmuster in einer bestimmten Weise verwendet), das als Advisor bezeichnet wird. Es ist ein Ratgeber, ob die Bereitstellung fortgesetzt werden soll oder nicht, es ist jedoch auch ein aktiver Fehlerbehandler, da es bei Rückfragen Sachen zurücksetzen 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/dumm ist. Es kann sehr komplex sein und sogar zutreffender sein, wenn es zusammen mit anderen Mustern verwendet wird.

7

Strategiemuster wird meistens speziell für Validierungen und Sortieralgorithmen verwendet. 

Lassen Sie mich mit einem einfachen praktischen Beispiel erklären 

enum Speed {
  SLOW, MEDIUM, FAST;
}

class Sorter {
 public void sort(int[] input, Speed speed) {
    SortStrategy strategy = null;
    switch (speed) {
    case SLOW:
        strategy = new SlowBubbleSortStrategy();
        break;
    case MEDIUM:
        strategy = new MediumInsertationSortStrategy();
        break;

    case FAST:
        strategy = new FastQuickSortStrategy();
        break;
    default:
        strategy = new MediumInsertationSortStrategy();
    }
    strategy.sort(input);
 }

}

interface SortStrategy {

    public void sort(int[] input);
}

class SlowBubbleSortStrategy implements SortStrategy {

   public void sort(int[] input) {
    for (int i = 0; i < input.length; i++) {
        for (int j = i + 1; j < input.length; j++) {
            if (input[i] > input[j]) {
                int tmp = input[i];
                input[i] = input[j];
                input[j] = tmp;
            }
        }
    }
    System.out.println("Slow sorting is done and the result is :");
    for (int i : input) {
        System.out.print(i + ",");
    }
  }

 }

class MediumInsertationSortStrategy implements SortStrategy {

public void sort(int[] input) {
    for (int i = 0; i < input.length - 1; i++) {
        int k = i + 1;
        int nxtVal = input[k];
        while (input[k - 1] > nxtVal) {
            input[k] = input[k - 1];
            k--;
            if (k == 0)
                break;
        }
        input[k] = nxtVal;
    }
    System.out.println("Medium sorting is done and the result is :");
    for (int i : input) {
        System.out.print(i + ",");
    }

 }

}

class FastQuickSortStrategy implements SortStrategy {

public void sort(int[] input) {
    sort(input, 0, input.length-1);
    System.out.println("Fast sorting is done and the result is :");
    for (int i : input) {
        System.out.print(i + ",");
    }
}

private void sort(int[] input, int startIndx, int endIndx) {
    int endIndexOrig = endIndx;
    int startIndexOrig = startIndx;
    if( startIndx >= endIndx)
        return;
    int pavitVal = input[endIndx];
    while (startIndx <= endIndx) {
        while (input[startIndx] < pavitVal)
            startIndx++;
        while (input[endIndx] > pavitVal)
            endIndx--;
        if( startIndx <= endIndx){
            int tmp = input[startIndx];
            input[startIndx] = input[endIndx];
            input[endIndx] = tmp;
            startIndx++;
            endIndx--;
        }
    }
    sort(input, startIndexOrig, endIndx);
    sort(input, startIndx, endIndexOrig);
 }

}  

Der Testcode hierfür lautet

public class StrategyPattern {
  public static void main(String[] args) {
    Sorter sorter = new Sorter();
    int[] input = new int[] {7,1,23,22,22,11,0,21,1,2,334,45,6,11,2};
    System.out.print("Input is : ");
    for (int i : input) {
        System.out.print(i + ",");
    }
    System.out.println();
    sorter.sort(input, Speed.SLOW);
 }

}

Das gleiche Beispiel stammt aus http://coder2design.com/strategy-pattern/

6
Jatinder Pal

Ein gutes Beispiel für ein Strategiemuster wäre in einem 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 Angriff () die Methode/der Algorithmus sein kann, der von den verwendeten Waffen abhängt. Wenn die konkreten Waffenklassen Schwert, Axt, Armbrust, BowAndArrow usw. wären, würden sie alle die Angriffsmethode () implementieren. Ich bin sicher, dass keine weitere Erklärung benötigt wird.

4

Sind Sie sicher, dass der Status einer "Bestellung" kein Statusmuster 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:

order.Ship();
  • Wenn die Versandart in Abhängigkeit von ihrem Status variiert, haben Sie ein Strategiemuster.
  • Wenn jedoch die Methode Ship () nur erfolgreich ist, wenn die Bestellung bezahlt wurde und die Bestellung noch nicht versendet wurde, haben Sie ein Statusmuster .

Das beste Beispiel für das Zustandsmuster (und andere Muster), das ich gefunden habe, war das Buch " Head First Design Patterns ", was erstaunlich ist. Eine knappe Sekunde wird David Cumps 'Blogserie von Mustern sein.

2
grootjans

Angenommen, Sie möchten einen Algorithmus schreiben, um den n-ten Xday eines bestimmten Monats und Jahres zu berechnen, z. B. den zweiten Montag im Oktober 2014. Sie möchten die Zeitklasse Android.text.format.Time von Android verwenden, um das Datum darzustellen, möchten aber auch um einen generischen Algorithmus zu schreiben, der auch auf Java.util.Calendar angewendet werden kann.

Das habe ich getan.

In DatetimeMath.Java:

public interface DatetimeMath { 
    public Object createDatetime(int year, int month, int day);

    public int getDayOfWeek(Object datetime);

    public void increment(Object datetime);
}

In TimeMath.Java:

public class TimeMath implements DatetimeMath {
    @Override
    public Object createDatetime(int year, int month, int day) {
        Time t = new Time();
        t.set(day, month, year);
        t.normalize(false);
        return t;
    }

    @Override
    public int getDayOfWeek(Object o) {
        Time t = (Time)o;
        return t.weekDay;
    }   

    @Override
    public void increment(Object o) {
        Time t = (Time)o;
        t.set(t.monthDay + 1, t.month, t.year);
        t.normalize(false);
    }
}

In OrdinalDayOfWeekCalculator.Java die Klasse mit dem generischen Algorithmus:

public class OrdinalDayOfWeekCalculator {   
    private DatetimeMath datetimeMath;

    public OrdinalDayOfWeekCalculator(DatetimeMath m) {
        datetimeMath = m;
    }

    public Object getDate(int year, int month, int dayOfWeek, int ordinal) {
        Object datetime = datetimeMath.createDatetime(year, month, 1);
        if (datetimeMath.getDayOfWeek(datetime) == dayOfWeek) {
            return datetime;
        } 
        int xDayCount = 0;
        while (xDayCount != ordinal) {
            datetimeMath.increment(datetime);
            if (datetimeMath.getDayOfWeek(datetime) == dayOfWeek) {
                xDayCount++;
            }
        }
        return datetime;
    }
}

In meiner Android-App würde ich so etwas nennen

OrdinalDayOfWeekCalculator odowc = 
        new OrdinalDayOfWeekCalculator(new TimeMath());
Time canadianThanksgiving = (Time)odowc.getDate(
        year, Calendar.OCTOBER, Time.MONDAY, 2);

Wenn ich den gleichen Algorithmus für Java.util.Calendar wiederverwenden möchte, würde ich einfach eine Klasse CalendarMath schreiben, die die drei Methoden in DatetimeMath implementiert und diese dann verwendet 

OrdinalDayOfWeekCalculator odowc2 = 
        new OrdinalDayOfWeekCalculator(new CalendarMath());
Calendar canadianThanksgivingCal = (Calendar)odowc2.getDate(
        year, Calendar.OCTOBER, Calendar.MONDAY, 2);
2
anomal

Wir mussten eine Provisioning-Schnittstelle eines Drittanbieters für eine Unternehmensplattform mit einer sehr komplizierten Datenbank erstellen. Die Übermittlung der zu liefernden Daten war eine Liste unserer Datentypen, die in unserer Anwendung in eine Prioritätswarteschlange gestellt wurden, sodass sie aufgrund von Abhängigkeiten in der richtigen Reihenfolge in die Datenbank geschrieben werden konnten.

Der Vorgang zum Schreiben dieser Daten war dann recht einfach. Sie sollten immer oben in der Prioritätswarteschlange stehen und dann eine Strategie wählen, die auf dem Typ des extrahierten Objekts basiert.

1
Coxy

Vor ein paar 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 Datenbankrepräsentation war ein Sternschema mit etwa 10 Zweigstellen. Eine der Folgen eines solchen Domänenobjekts mit hoher Gewichtung ist, dass wir andere Domänenobjekte erstellen mussten, die dasselbe Schema darstellten, wenn auch mit weniger Gewicht. Also habe ich die anderen leichtgewichtigen Objekte dazu gebracht, dieselbe Schnittstelle zu implementieren. Ansonsten hatten wir:

public interface CollectibleElephant { 
    long getId();
    String getName();
    long getTagId();
}

public class Elephant implements CollectibleElephant { ... }
public class BabyElephant implements CollectibleElephant { ... }

Ursprünglich wollte ich CollectibleElephant verwenden, um Elephants zu sortieren. Ziemlich schnell machten sich meine Teamkollegen auf CollectibleElephant, um Sicherheitsüberprüfungen durchzuführen, sie zu filtern, wenn sie an die GUI gesendet wurden usw.

1
Alan
public class StrategyDemo {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();

        Item item1 = new Item("1234", 10);
        Item item2 = new Item("5678", 40);

        cart.addItem(item1);
        cart.addItem(item2);

        // pay by Paypal
        cart.pay(new PaypalStrategy("[email protected]", "mypwd"));

        // pay by credit card
        cart.pay(new CreditCardStrategy("Pankaj Kumar", "1234567890123456", "786", "12/15"));
    }
}

interface PaymentStrategy {
    public void pay(int amount);
}

class CreditCardStrategy implements PaymentStrategy {

    private String name;
    private String cardNumber;
    private String cvv;
    private String dateOfExpiry;

    public CreditCardStrategy(String nm, String ccNum, String cvv, String expiryDate) {
        this.name = nm;
        this.cardNumber = ccNum;
        this.cvv = cvv;
        this.dateOfExpiry = expiryDate;
    }

    @Override
    public void pay(int amount) {
        System.out.println(amount + " paid with credit/debit card");
    }

}

class PaypalStrategy implements PaymentStrategy {

    private String emailId;
    private String password;

    public PaypalStrategy(String email, String pwd) {
        this.emailId = email;
        this.password = pwd;
    }

    @Override
    public void pay(int amount) {
        System.out.println(amount + " paid using Paypal.");
    }

}

class Item {

    private String upcCode;
    private int price;

    public Item(String upc, int cost) {
        this.upcCode = upc;
        this.price = cost;
    }

    public String getUpcCode() {
        return upcCode;
    }

    public int getPrice() {
        return price;
    }

}

class ShoppingCart {

    // List of items
    List<Item> items;

    public ShoppingCart() {
        this.items = new ArrayList<Item>();
    }

    public void addItem(Item item) {
        this.items.add(item);
    }

    public void removeItem(Item item) {
        this.items.remove(item);
    }

    public int calculateTotal() {
        int sum = 0;
        for (Item item : items) {
            sum += item.getPrice();
        }
        return sum;
    }

    public void pay(PaymentStrategy paymentMethod) {
        int amount = calculateTotal();
        paymentMethod.pay(amount);
    }
}
1
Vivek Goel

Ich habe den Strategieansatz in einer ziemlich komplexen Engine in einer Anwendung verwendet, die ein gutes Beispiel ist. Im Wesentlichen bestand die Rolle der Engine darin, zunächst eine Liste der Personen zu finden, die ein Widget hatten. Die zweite Rolle bestand darin, herauszufinden, welche 10 besten Benutzer ein Widget auf der Grundlage einer unbekannten Anzahl von Parametern hatten (z. B. Preisdistanz vorheriges Geschäft zusammen) , Menge auf Lager, Versandoptionen etc etc etc ...)

Im Wesentlichen haben wir das Problem in zwei Strategien aufgeteilt: Die erste war das Abrufen von Daten, da wir wussten, dass wir mehrere Quellen für unsere Widgets hatten, und wir mussten in der Lage sein, die Daten abzurufen und in eine gemeinsame Struktur umzuwandeln.

Wir haben dann auch festgestellt, dass wir mehrere Algorithmen hatten, von denen einige auf der Gewichtung der Parameter basierten. Andere waren sehr seltsam und eigenartig, und ich konnte ihnen nicht gerecht werden, ohne Visios und Diagramme herauszuziehen die besten Leute auswählen. 

Unser Service selbst war genau das, was im Wesentlichen die Inputs und Outputs definierte und die Daten ein wenig normalisierte. Außerdem benutzte er ein Providermuster, um die anwendungsspezifischen Datenprovider und Algorithmenanbieter einzubinden, die die Strategie verwendeten. Dies war ein ziemlich effektives System.

Wir hatten einige Debatten, ob wir eine Strategie oder ein Schablonenmuster verwenden, die wir niemals gelöst haben.

1
JoshBerke

Aus Wikipedia 

Bei der Computerprogrammierung ist das Strategiemuster (auch als Richtlinienmuster bekannt) ein Verhaltenssoftwaredesignmuster, das die Auswahl eines Algorithmus zur Laufzeit ermöglicht. Anstatt einen einzelnen Algorithmus direkt zu implementieren, erhält der Code Laufzeitanweisungen, welche in einer Familie von Algorithmen zu verwenden sind

In der Windows Paint-Anwendung sehen Sie ein Strategiemuster, in dem Sie Form und Farbe unabhängig voneinander in verschiedenen Abschnitten 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, können Sie anstelle der Option "Roter Kreis" den Kreis und die Farbe Ihrer Wahl auswählen.

Shape redCircle = new RedCircle(); // Without stretegy Pattern
Shaped redCircle = new Shape("red","circle"); // With Strategy pattern

Ohne Strategiemuster wird die Anzahl der Klassen mit dem kartesischen Produkt von Form und Farbe erhöht. Auch die Schnittstelle ändert sich für jede Implementierung.

0
bharanitharan