108 votes

Exemple concret du modèle de stratégie

J'ai lu des articles sur le Principe de l'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 peux penser est l'utilisation de différentes classes de validation en fonction du statut d'une "commande".

J'ai lu quelques articles en ligne, mais ils ne décrivent généralement pas une véritable 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 ?

112voto

OscarRyz Points 82553

Qu'en est-il de ceci :

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 gb).

Pour les fichiers volumineux, vous pouvez utiliser une autre stratégie, où 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 serait le même :

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

}

El

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

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

J'espère que cela vous aidera.

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

76voto

Ceryl Wiltink Points 599

Encore une fois, il s'agit d'un ancien article, mais il revient toujours dans les recherches. Je vais donc ajouter deux autres exemples (le code est en C#). J'aime absolument le modèle Strategy car il m'a sauvé la mise de nombreuses fois lorsque les chefs de projet m'ont dit : "Nous voulons que l'application fasse 'X', mais 'X' n'est pas encore clair et il peut changer dans un avenir proche". Ce site vidéo expliquant le modèle de stratégie utilise StarCraft comme exemple.

Les choses qui entrent dans cette catégorie :

  • Triage : Nous voulons trier ces chiffres, mais nous ne savons pas si nous allons utiliser BrickSort, BubbleSort ou un autre type de tri.

  • Validation : Nous devons vérifier les éléments selon "une certaine règle", mais la nature de cette règle n'est pas encore claire, et nous pouvons en imaginer de nouvelles.

  • Jeux : Nous voulons que le joueur puisse marcher ou courir lorsqu'il se déplace, mais peut-être qu'à l'avenir, il devrait aussi être capable de nager, voler, se téléporter, s'enfouir sous terre, etc.

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

  • Sortie : Nous avons besoin de sortir X sous la forme d'une simple chaîne de caractères, mais plus tard cela peut être un CSV, XML, JSON, etc.


Exemples

J'ai un projet dans lequel les utilisateurs peuvent attribuer des produits à des personnes dans une base de données. Cette affectation d'un produit à une personne a un statut qui est soit "Approuvé" soit "Refusé", qui dépend de certaines règles de gestion. 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'article est supérieure à 50, son statut est refusé, etc.

Or, au moment du développement, ces règles commerciales ne sont pas encore toutes parfaitement claires, et de nouvelles règles peuvent apparaître à tout moment. La puissance du modèle de stragety est que j'ai créé un RuleAgent, qui reçoit une liste de 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 je lui demande de valider une attribution. Il va passer en revue toutes ses règles. Celles-ci, parce qu'elles implémentent toutes la même interface, ont toutes l'attribut IsApproved et renvoie false si l'un d'entre eux renvoie false.

Maintenant, lorsque par exemple le manager arrive soudainement et dit, nous devons également refuser toutes les affectations aux stagiaires, ou toutes les affectations aux personnes qui font des heures supplémentaires.... Vous créez de nouvelles classes comme ça :

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 qu'il n'est pas nécessaire de continuer à ajouter ou à supprimer des déclarations if ou du code, il suffit de créer une nouvelle classe de règles qui implémente l'interface IRUle et d'intervertir les règles lorsque cela est 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 Unit-test de l'application.

Il construit un site Web dont une page affiche des articles en fonction de leur popularité. Cependant, "populaire" peut être beaucoup de choses (le plus de vues, le plus d'abonnés, la date de création, le plus d'activité, le moins de commentaires, etc), et dans le cas où la direction ne sait pas encore exactement comment ordonner, et peut vouloir expérimenter avec différents ordonnancements à une date ultérieure. Vous créez une interface (IOrderAlgorithm ou autre) 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", un "ActivityOrderer", etc... Et il suffit de les changer quand de nouvelles exigences apparaissent.

25voto

Ravindra babu Points 5571

Notes clés :

  1. Stratégie est un modèle de conception comportementale. Il est utilisé pour passer d'une famille d'algorithmes à une autre.

  2. Ce modèle contient une stratégie abstraite interface et beaucoup béton les mises en œuvre de la stratégie ( algorithmes ) de cette interface.

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

Diagramme UML de wikipedia

enter image description here

Un exemple concret : Compagnies aériennes offrant des réductions pendant certains mois (juillet-décembre) . Vous pouvez avoir un Tarif qui décide des options de prix en fonction du nombre de mois.

Jetez un coup d'œil à un exemple simple. Cet exemple peut être étendu aux applications de vente au détail en ligne, qui permettent d'accorder facilement des remises sur les articles du panier d'achat lors de journées spéciales ou d'heures heureuses.

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

}

sortie :

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 :

stratégie modèle par dzone

stratégie motif par sourcemaking

12voto

Eric Pohl Points 1258

Je peux penser à plusieurs exemples assez simples :

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

    byte[] compress(byte[] input) ;

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

12voto

Fabian Steeg Points 24261

Une utilisation courante du modèle de stratégie consiste à définir des stratégies de tri personnalisées (dans des langages dépourvus de fonctions d'ordre supérieur), par exemple pour trier une liste de chaînes de caractères 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 manière similaire, les stratégies peuvent être utilisées pour des requêtes natives avec des bases de données objet, par exemple dans db4o :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X