Exemple du monde réel du modèle de stratégie

95

J'ai lu sur le principe OCP et comment utiliser le modèle de stratégie pour y parvenir.

J'allais essayer d'expliquer cela à quelques personnes, mais le seul exemple auquel je puisse penser est l'utilisation de différentes classes de validation basées sur le statut d'une «commande».

J'ai lu quelques articles en ligne, mais ceux-ci ne décrivent généralement pas une vraie raison d'utiliser la stratégie, comme la génération de rapports / factures / validation, etc.

Y a-t-il des exemples concrets où vous pensez qu'un modèle de stratégie est courant?

Ravindra babu
la source

Réponses:

100

Et ça:

Vous devez crypter un fichier.

Pour les petits fichiers, vous pouvez utiliser la stratégie «en mémoire», où le fichier complet est lu et conservé en mémoire (disons pour les fichiers <1 Go)

Pour les fichiers volumineux, vous pouvez utiliser une autre stratégie, dans laquelle des parties du fichier sont lues en mémoire et les résultats partiellement chiffrés sont stockés dans des fichiers tmp.

Il peut s'agir de deux stratégies différentes pour la même tâche.

Le code client aurait le même aspect:

 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.
         }

}

le

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

Renvoie l'instance de stratégie correcte pour le chiffrement.

J'espère que ça aide.

(Je ne sais même pas si Cipher est le bon mot: P)

OscarRyz
la source
8
Votre exemple n'est-il pas plus un modèle d'usine? Aussi je pense que cela ne fonctionnera pas en C # par exemple. Votre méthode "getCipher ()" est une méthode statique mais en C # vous ne pouvez pas définir une méthode statique sur une interface (ni en Java je pense mais pour cela je ne suis pas sûr).
FrenchData du
10
Ils vont ensemble. L'usine crée la stratégie, mais la stratégie elle-même contient l'algorithme pour effectuer (essentiellement) la même opération. La stratégie peut également être modifiée lors de l'exécution. À propos de la méthode d'usine, vous avez raison, je l'ai changé.
OscarRyz
Pour ajouter le point Osacars, sans usine, cela peut être créé sans usine Cipher C =null; if (file.size() <= 2048) { C = new InMemoryCipherStrategy(); } else { c= SwaptToDiskCipher (); }
Abhijit Mazumder
D'accord avec @FrenchData. Tout en étant un excellent exemple, la présence de CipherFactorypeut dérouter ceux qui ne sont pas familiers avec le modèle de stratégie.
user487772
1
Le modèle d'usine est sur la création, la stratégie est sur le comportement. Il y a un droit légèrement différent?
nhoxbypass
62

Encore une fois, un ancien message apparaît toujours dans les recherches, je vais donc ajouter deux autres exemples (le code est en C #). J'adore le modèle de stratégie car il m'a souvent sauvé les fesses lorsque les chefs de projet disent: «Nous voulons que l'application fasse 'X', mais 'X' n'est pas encore clair et cela peut changer dans un proche avenir. " Cette vidéo expliquant le modèle de stratégie utilise StarCraft comme exemple.

Trucs qui entrent dans cette catégorie:

  • Tri: Nous voulons trier ces nombres, mais nous ne savons pas si nous allons utiliser BrickSort, BubbleSort ou un autre tri

  • Validation: Nous devons vérifier les éléments selon "Certaines règles", mais ce que sera cette règle n'est pas encore claire et nous pourrions en penser à de nouvelles.

  • Jeux: Nous voulons que le joueur marche ou coure quand il bouge, mais peut-être qu'à l'avenir, il devrait également être capable de nager, voler, se téléporter, creuser sous terre, etc.

  • Stockage des informations: nous voulons que l'application stocke les informations dans la base de données, mais plus tard, elle devra peut-être enregistrer un fichier ou effectuer un appel Web

  • Sortie: Nous devons générer X sous forme de chaîne simple, mais plus tard, il peut s'agir d'un CSV, XML, JSON, etc.


Exemples

J'ai un projet où les utilisateurs peuvent attribuer des produits à des personnes dans une base de données. Cette attribution d'un produit à une personne a un statut qui est "Approuvé" ou "Refusé", qui dépend de certaines règles métier. Par exemple: si un utilisateur attribue un produit à une personne d'un certain âge, son statut doit être refusé; Si la différence entre deux champs de l'élément est supérieure à 50, son statut est refusé, etc.

Aujourd'hui, au moment du développement, ces règles commerciales ne sont pas encore complètement claires et de nouvelles règles pourraient apparaître à tout moment. Le pouvoir du modèle stragety est que j'ai créé un RuleAgent, qui reçoit une liste d'IRules.

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

Au moment d'attribuer un produit à une personne, je crée un RuleAgent, je lui donne une liste de règles (qui implémentent toutes IRule) et lui demande de valider une affectation. Cela passera par toutes ses règles. Qui, parce qu'ils implémentent tous la même interface, ont tous la IsApprovedméthode et retournent false si l'un d'eux retourne false.

Maintenant, lorsque, par exemple, le gestionnaire arrive soudainement et dit, nous devons également refuser toutes les affectations à des stagiaires, ou toutes les affectations à des personnes qui font des heures supplémentaires ... Vous créez de nouveaux cours comme celui-ci:

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;
    }
}

Vous voyez que vous n'avez pas à continuer à ajouter ou à supprimer des instructions if ou du code, créez simplement une nouvelle classe de règles qui implémente l'interface IRUle et remplacez-les si nécessaire.


Un autre excellent exemple: la série de vidéos de Scott Allen sur http://www.asp.net/mvc/pluralsight où il utilise le modèle de stratégie dans la partie Test unitaire de l'application

Il crée un site Web qui a une page qui affiche des éléments en fonction de la popularité. Cependant, "Populaire" peut être composé de plusieurs éléments (la plupart des vues, la plupart des abonnés, la date de création, la plupart des activités, le moins de commentaires, etc.), et dans le cas où la gestion des cas ne sait pas encore exactement comment commander, et peut vouloir expérimenter différentes commandes à une date ultérieure. Vous créez une interface (IOrderAlgorithm ou quelque chose) avec une méthode de commande, et laissez un objet Orderer déléguer la commande à une implémentation concrète de l'interface IOrderAlgorithm. Vous pouvez créer un "CommentOrderer", "ActivityOrderer", etc ... Et les changer simplement lorsque de nouvelles exigences apparaissent.

Céryl Wiltink
la source
Je sais que c'est un peu hors de portée de la question, mais qu'est-ce qui vient ensuite? Nous l'avons InternRulemaintenant mais comment déclenchons-nous OvertimeRule? Comment pouvons-nous nous assurer que toute logique appelée OvertimeRule.IsApprovedmaintenant appelle également InternRule.IsApproved?
Spencer Ruport
13

Notes clés:

  1. La stratégie est un modèle de conception comportementale. Il est utilisé pour basculer entre les familles d'algorithmes.

  2. Ce modèle contient une interface de stratégie abstraite et de nombreuses implémentations de stratégie concrète ( algorithmes ) de cette interface.

  3. L'application utilise uniquement l' interface de stratégie . En fonction de certains paramètres de configuration, la stratégie concrète sera étiquetée à l' interface .

Diagramme UML de wikipedia

entrez la description de l'image ici

Un exemple concret : les compagnies aériennes offrent des réductions pendant certains mois (juillet-décembre) . Vous pouvez avoir un module Fare , qui décide des options de tarification en fonction du numéro du mois.

Jetez un œil à un exemple simple. Cet exemple peut être étendu aux applications de vente au détail en ligne, qui offrent facilement des rabais sur les articles du panier lors de jours spéciaux / happy hours.

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);
    }

}

production:

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

Articles utiles:

modèle de stratégie par dzone

modèle de stratégie par sourcemaking

Ravindra babu
la source
12

Je peux penser à plusieurs exemples assez simples:

  • Trier une liste. La stratégie est la comparaison utilisée pour décider lequel des deux éléments de la liste est "Premier"
  • Vous pouvez avoir une application dans laquelle l'algorithme de tri lui-même (QuickSort, HeapSort, etc.) peut être choisi au moment de l'exécution
  • Appenders, dispositions et filtres dans Log4Net et Log4j
  • Gestionnaires de mise en page dans les boîtes à outils de l'interface utilisateur
  • Compression de données. Vous pourriez avoir une interface ICompressor dont la seule méthode ressemble à ceci:

    byte [] compress (byte [] input);

    Vos classes de compression concrètes peuvent être des choses comme RunLengthCompression, DeflateCompression, etc.

Eric Pohl
la source
9

Un usage courant du modèle de stratégie est de définir des stratégies de tri personnalisées (dans les langages sans fonctions d'ordre supérieur), par exemple pour trier une liste de chaînes par longueur en Java, en passant une classe interne anonyme (une implémentation de l'interface de stratégie):

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);

De la même manière, des stratégies peuvent être utilisées pour des requêtes natives avec des bases de données d'objets, par exemple dans db4o:

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

J'ai une application qui synchronise chaque jour sa base d'utilisateurs avec notre annuaire d'entreprise. Les utilisateurs sont éligibles ou non éligibles en fonction de leur statut dans l'Université. Chaque jour, le programme d'approvisionnement passe en revue et s'assure que ceux qui sont censés être éligibles sont approvisionnés dans l'application et ceux qui ne le sont pas sont déprovisionnés (en fait selon un algorithme de dégradation gracieuse, mais ce n'est pas la question). Samedi, je fais une mise à jour plus approfondie qui synchronise certaines propriétés de chaque utilisateur et m'assure qu'ils ont la bonne éligibilité. À la fin du mois, j'effectue un traitement de facturation en fonction de l'utilisation pour ce mois.

J'utilise un modèle de stratégie composable pour effectuer cette synchronisation. Le programme principal choisit essentiellement une stratégie de maître en fonction du jour de la semaine (synchroniser uniquement les changements / synchroniser tout) et l'heure du semestre par rapport au calendrier académique. Si le cycle de facturation se termine, il le compose également avec une stratégie de facturation. Il exécute ensuite la stratégie choisie via une interface standard.

Je ne sais pas à quel point c'est courant, mais j'avais l'impression que c'était un ajustement parfait pour le modèle de stratégie.

Tvanfosson
la source
C'est un très bon exemple. En outre, il vous indique clairement la différence entre le modèle de commande et de stratégie en un mot - l'intention. "Le programme principal choisit essentiellement une stratégie principale en fonction du jour de la semaine"
Utsav T
7

Je sais que c'est une vieille question, mais je pense avoir un autre exemple intéressant que j'ai mis en œuvre récemment.

Ceci est un exemple très pratique du modèle de stratégie utilisé dans un système de livraison de documents.

J'avais un système de livraison PDF qui recevait une archive contenant beaucoup de documents et quelques métadonnées. Sur la base des métadonnées, il a décidé où placer le document; par exemple, selon les données, je pouvais stocker le document A, Bou les Csystèmes de stockage, ou un mélange des trois.

Différents clients utilisaient ce système, et ils avaient des exigences différentes de gestion des annulations / erreurs en cas d'erreurs: on voulait que le système de livraison s'arrête à la première erreur, laisse tous les documents déjà livrés dans leurs stockages, mais arrête le processus et ne livre rien d'autre ; un autre voulait qu'il revienne en arrière Ben cas d'erreurs lors du stockage C, mais laisser tout ce qui était déjà livré A. Il est facile d'imaginer qu'un troisième ou un quatrième aura également des besoins différents.

Pour résoudre le problème, j'ai créé une classe de livraison de base qui contient la logique de livraison, ainsi que des méthodes pour restaurer des éléments de tous les stockages. Ces méthodes ne sont pas réellement appelées directement par le système de livraison en cas d'erreurs. Au lieu de cela, la classe utilise Dependency Injection pour recevoir une classe "Rollback / Error Handling Strategy" (basée sur le client utilisant le système), qui est appelée en cas d'erreurs, qui à son tour appelle les méthodes de rollback si cela est approprié pour cette stratégie.

La classe de livraison elle-même rapporte ce qui se passe dans la classe de stratégie (quels documents ont été livrés à quels stockages et quels échecs se sont produits), et chaque fois qu'une erreur se produit, elle demande à la stratégie si elle doit continuer ou non. Si la stratégie dit "arrêtez-le", la classe appelle la méthode "cleanUp" de la stratégie, qui utilise les informations précédemment rapportées pour décider quelles méthodes de restauration appeler à partir de la classe de livraison, ou simplement ne rien faire.

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

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

J'ai donc maintenant deux stratégies différentes: l'une est la QuitterStrategy(qui se ferme à la première erreur et ne nettoie rien) et l'autre est la MaximizeDeliveryToAStrategy(qui essaie autant que possible de ne pas abandonner le processus et de ne jamais annuler les éléments livrés au stockage A, mais annule des éléments deB si la livraison Céchoue).

D'après ce que je comprends, c'est un exemple du modèle de stratégie. Si vous (oui, vous lisez) pensez que je me trompe, veuillez commenter ci-dessous et me le faire savoir. Je suis curieux de savoir ce qui constituerait une utilisation «pure» du modèle de stratégie et quels aspects de ma mise en œuvre enfreignent la définition. Je pense que cela a l'air un peu drôle car l'interface de stratégie est un peu grosse. Tous les exemples que j'ai vus jusqu'à présent n'utilisent qu'une seule méthode, mais je pense toujours que cela encapsule un algorithme (si un élément de logique métier peut être considéré comme un algorithme, ce que je pense que c'est le cas).

Étant donné que la stratégie est également notifiée des événements lors de l'exécution de la livraison, elle peut également être considérée comme un observateur , mais c'est une autre histoire.

Après avoir fait un peu de recherche, il semble que ce soit un "modèle composite" (comme MVC, un modèle qui utilise plusieurs modèles de conception en dessous d'une manière particulière) appelé le conseiller . C'est un conseiller pour savoir si la livraison doit se poursuivre ou non, mais c'est aussi un gestionnaire d'erreurs actif car il peut annuler des choses à la demande.

Quoi qu'il en soit, c'est un exemple assez complexe qui pourrait donner l'impression que les utilisations du modèle de stratégie sont trop simples / idiotes. Il peut être vraiment complexe et même plus applicable lorsqu'il est utilisé avec d'autres modèles.

Gui Prá
la source
6

Le modèle de stratégie est le modèle le plus couramment utilisé, spécialement pour les validations et les algorithmes de tri.

Laissez-moi vous expliquer avec un exemple pratique simple

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);
 }

}  

Le code de test pour cela est

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);
 }

}

Le même exemple est tiré de http://coder2design.com/strategy-pattern/

Jatinder Pal
la source
Différentes utilisations du modèle de stratégie: Validations: Lorsqu'il y a beaucoup de validations à faire dans votre code. Différents algorithmes: en particulier lorsque différents algorithmes de tri peuvent être utilisés, par exemple le tri à bulles ou le tri rapide. Stockage d'informations: lorsque nous pourrions avoir des informations à différents endroits, par exemple une base de données ou un système de fichiers. Analyse: lors de l'analyse, nous pouvons utiliser une stratégie différente pour différentes entrées. Stratégies de filtrage. Stratégies de mise en page.
Jatinder Pal
5

Un bon exemple de modèle de stratégie serait dans un jeu où nous pouvons avoir différents personnages et chaque personnage peut avoir plusieurs armes à attaquer mais à la fois ne peut utiliser qu'une seule arme. Nous avons donc le personnage comme contexte, par exemple le roi, le commandant, le chevalier, le soldat et l'arme comme stratégie où l'attaque () pourrait être la méthode / l'algorithme qui dépend des armes utilisées. Donc, si les classes d'armes concrètes étaient Sword, Axe, Crossbow, BowAndArrow etc., elles implémenteraient toutes la méthode attack (). Je suis sûr que des explications supplémentaires ne sont pas nécessaires.

Sandipan Karmakar
la source
1
Je pensais que la réponse acceptée était censée parler de cet exemple :)
Jeancarlo Fontalvo
2

J'ai utilisé l'approche stratégique dans un moteur assez complexe dans une application qui en est un bon exemple. Essentiellement, le rôle du moteur était d'aller chercher d'abord une liste de personnes qui avaient un widget, son deuxième rôle était de déterminer quelles étaient les 10 meilleures personnes avec un widget basé sur un nombre inconnu de paramètres (des choses comme la distance de prix des affaires précédentes ensemble , montant en stock, options d'expédition etc etc etc ...)

Essentiellement, nous avons divisé le problème en deux stratégies, la première étant la récupération de données, car nous savions que nous avions plusieurs sources de nos widgets et que nous devions être en mesure d'obtenir les données et de les transformer en une structure commune.

Nous avons également réalisé que nous avions plusieurs algorithmes, certains étaient basés sur la pondération des paramètres, d'autres étaient très bizarres et propices et je ne pouvais pas leur rendre justice sans sortir des visios et des graphiques et bien vous voyez l'image, nous avions beaucoup d'algorithmes pour sélectionner les meilleures personnes.

Notre service lui-même était très simple: il définissait essentiellement les entrées, les sorties et normalisait les données.Il utilisait également un modèle de fournisseur pour connecter les fournisseurs de données et les fournisseurs d'algorithmes spécifiques à l'application qui utilisaient la stratégie. C'était un système assez efficace.

Nous avons eu des débats si nous utilisions une stratégie ou un modèle de modèle que nous n'avons jamais résolu.

JoshBerke
la source
2

Êtes-vous sûr que l'état d'une "commande" n'est pas un modèle d'état? J'ai le sentiment qu'une commande ne sera pas traitée différemment selon son statut.

Prenons par exemple la méthode Expédier à la Commande:

order.Ship();
  • Si la méthode d'expédition varie en fonction de son statut, vous avez un modèle de stratégie.
  • Si toutefois la méthode Ship () ne réussit que lorsque la commande a été payée et que la commande n'a pas encore été expédiée, vous avez un modèle d'état.

Le meilleur exemple du modèle d'état (et d'autres modèles) que j'ai trouvé était dans le livre " Head First Design Patterns ", ce qui est incroyable. La série de modèles de blogging de David Cumps sera une seconde proche .

grootjans
la source
2

Supposons que vous souhaitiez écrire un algorithme pour calculer le nième Xday d'un mois et d'une année donnés, par exemple, le deuxième lundi d'octobre 2014. Vous souhaitez utiliser la classe Time d'Android android.text.format.Timepour représenter la date, mais vous souhaitez également écrire un algorithme générique cela peut également s'appliquer à java.util.Calendar.

C'est ce que j'ai fait.

Dans DatetimeMath.java:

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

    public int getDayOfWeek(Object datetime);

    public void increment(Object datetime);
}

Dans 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);
    }
}

Dans OrdinalDayOfWeekCalculator.java, la classe avec l'algorithme générique:

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;
    }
}

Dans mon application Android, j'appellerais quelque chose comme

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

Si je veux réutiliser le même algorithme pour java.util.Calendar, j'écrirais simplement une classe CalendarMath qui implémente les trois méthodes dans DatetimeMath, puis j'utiliserais

OrdinalDayOfWeekCalculator odowc2 = 
        new OrdinalDayOfWeekCalculator(new CalendarMath());
Calendar canadianThanksgivingCal = (Calendar)odowc2.getDate(
        year, Calendar.OCTOBER, Calendar.MONDAY, 2);
anomalie
la source
2
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);
    }
}
Vivek Goel
la source
1

Il y a quelques semaines, j'ai ajouté une interface Java commune qui a été implémentée par l'un de nos objets de domaine. Cet objet de domaine a été chargé à partir de la base de données et la représentation de la base de données était un schéma en étoile avec plus de 10 branches. L'une des conséquences d'avoir un objet de domaine aussi lourd est que nous avons dû créer d'autres objets de domaine qui représentaient le même schéma, bien que moins lourds. J'ai donc fait en sorte que les autres objets légers implémentent la même interface. En d'autres termes, nous avions:

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

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

À l'origine, je voulais utiliser CollectibleElephantpour trier Elephants. Assez rapidement, mes coéquipiers se sont précipités CollectibleElephantpour exécuter des contrôles de sécurité, les filtrer au fur et à mesure qu'ils étaient envoyés à l'interface graphique, etc.

Alan
la source
1

Nous avons dû créer une interface de provisioning tierce pour une plateforme d'entreprise avec une base de données très compliquée. La soumission des données à approvisionner était une liste de nos types de données qui ont été placés dans une file d'attente prioritaire dans notre application afin qu'ils puissent être écrits dans la base de données dans le bon ordre en raison des dépendances.

Le processus d'écriture de ces données était alors assez simple, continuez à apparaître en haut de la file d'attente prioritaire, puis choisissez une stratégie en fonction du type d'objet que vous extrayez.

Coxy
la source
0

De wikipedia

En programmation informatique, le modèle de stratégie (également appelé modèle de stratégie) est un modèle de conception de logiciel comportemental qui permet de sélectionner un algorithme au moment de l'exécution. Au lieu d'implémenter directement un seul algorithme, le code reçoit des instructions d'exécution indiquant lequel dans une famille d'algorithmes utiliser

Dans l'application Windows Paint, vous pouvez voir un modèle de stratégie dans lequel vous pouvez choisir la forme et la couleur indépendamment dans différentes sections. Ici, la forme et la couleur sont les algorithmes qui peuvent être modifiés à l'exécution.

Si vous souhaitez dessiner un cercle de couleur rouge, plutôt que de fournir une option de «RedCircle», ils vous permettent de choisir le cercle et une couleur de votre choix.

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

Sans modèle de stratégie, le nombre de classes augmentera avec le produit cartésien de la forme et de la couleur. L'interface change également pour chaque implémentation.

bharanitharan
la source
0

Imaginez un jeu de tir avec des ennemis IA par exemple. Vous voulez qu'ils se battent continuellement de différentes manières en fonction de ce qui se passe. Avec le modèle de stratégie, vous pouvez continuellement boucler et changer dynamiquement la façon dont une action ou une action spécifique sera effectuée.

interface FightingStategy{
    public void fight();
}
public Defense implements FightingStrategy{
    public void figth(){
        ... hide behind wall to shoot
    }
}
public Berserker implements FightingStrategy{
    public void fight(){
        ... run towards you, headrolls and shoots
    }
}
public Dead implements FightingStrategy{
    public void fight(){
        ... is dead, doesn't move
    }
}

public AiShooter{

    FightingStrategy fightingStrategy;

    public AiShooter(){
        fightStrategy = new Berserker();
    }

    public void fight(){
        this.fightingStrategy.fight();
    }

    public void changeStrategy(FightingStrategy f){
        this.fightingStrategy = f;
    }
}

public static void main(){

    ... create list of AiShooters...
    while (condition){
        list.forEach(shooter -> shooter.fight());
    }
    ... you shoot back
    list.ForEach(shooter -> shooter.changeStrategy(new 
Defense()));

    ... you kill one
    list.get(n).changeStrategy(new Dead());
}
Cédric S
la source