J'ai lu sur le principe OCP et sur la façon d'utiliser le modèle de stratégie pour accomplir cela.
J'allais essayer d'expliquer cela à quelques personnes, mais le seul exemple auquel je peux penser consiste à utiliser différentes classes de validation en fonction du statut d'une "commande".
J'ai lu quelques articles en ligne, mais ceux-ci ne décrivent généralement pas une raison réelle d'utiliser la stratégie, telle que la génération de rapports/factures/validation, etc.
Existe-t-il des exemples concrets dans lesquels un modèle de stratégie est commun?
Et ça:
Vous devez chiffrer un fichier.
Pour les petits fichiers, vous pouvez utiliser la stratégie "en mémoire", dans laquelle le fichier complet est lu et conservé en mémoire (par exemple, pour les fichiers <1 Go).
Pour les fichiers volumineux, vous pouvez utiliser une autre stratégie: des parties du fichier sont lues en mémoire et des résultats chiffrés partiels sont stockés dans des fichiers tmp.
Celles-ci peuvent être deux stratégies différentes pour la même tâche.
Le code du 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() );
Renverrait 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)
Encore une fois, une ancienne publication, mais toujours sur les recherches alors je vais ajouter deux autres exemples (Code est en C #). J'adore le modèle Strategy car il m'a souvent épargné le fardeau lorsque les responsables du projet ont déclaré: "Nous voulons que l'application utilise" X ", mais" X "n'est pas encore clair et peut changer dans un proche avenir. " Cette vidéo expliquant le modèle de stratégie , utilise StarCraft comme exemple.
Choses qui tombe dans cette catégorie:
Tri: 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 en fonction de "Une règle", mais nous ne savons pas encore quelle sera cette règle et nous pourrions penser à de nouveaux.
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, se terrer sous terre, etc.
Stockage des informations: nous souhaitons que l’application stocke des informations dans la base de données, mais il peut être nécessaire ultérieurement de pouvoir enregistrer un fichier ou effectuer un appel Web.
Sortie: Nous devons sortir X en tant que chaîne simple, mais peut être plus tard un fichier CSV, XML, JSON, etc.
Exemples
J'ai un projet où les utilisateurs peuvent assigner des produits aux personnes d'une base de données. Cette affectation d'un produit à une personne a un statut "Approuvé" ou "Refusé", qui dépend de certaines règles de gestion. Par exemple: si un utilisateur assigne 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.
Au moment du développement, ces règles de gestion ne sont pas encore tout à fait claires et de nouvelles règles peuvent apparaître à tout moment. La puissance du modèle de stragety réside dans le fait que j'ai créé un agent RuleAgent, qui se voit attribuer une liste d'IRules.
public interface IRule {
bool IsApproved(Assignment assignment);
}
Au moment d'assigner un produit à une personne, je crée un RuleAgent, lui donne une liste de règles (qui implémentent toutes IRule) et lui demande de valider une affectation. Il va parcourir toutes ses règles. Comme ils implémentent tous la même interface, ils utilisent tous la méthode IsApproved
et renvoient false si aucun d’entre eux ne renvoie false.
Maintenant, lorsque, par exemple, le responsable arrive soudainement et dit, nous devons également refuser toutes les tâches à des stagiaires, ou toutes les tâches à des personnes effectuant 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 besoin de 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 lorsque cela est nécessaire.
Autre exemple intéressant: 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 de la partie de test de l’application.
Il construit un site Web qui a une page qui affiche des éléments basés sur la popularité. Cependant, "populaire" peut prendre plusieurs formes (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 la gestion des cas, il ne sait pas encore exactement comment commander les commandes à une date ultérieure. Vous créez une interface (IOrderAlgorithm ou quelque chose de ce type) avec une méthode de commande et laissez un objet Orderer-delegate déléguer la commande à une implémentation concrète de l'interface IOrderAlgorithm. Vous pouvez créer un "CommentOrderer", un "ActivityOrderer", etc ... et simplement les désactiver lorsque de nouvelles exigences apparaissent.
Je peux penser à plusieurs exemples assez simples:
Compression de données. Vous pouvez avoir une interface ICompressor dont la seule méthode ressemble à ceci:
octet [] compresser (octet [] entrée);
Vos classes de compression concrètes peuvent être des choses comme RunLengthCompression, DeflateCompression, etc.
Une utilisation courante du modèle de stratégie consiste à définir des stratégies de tri personnalisées (dans des langues 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 manière similaire, des stratégies peuvent être utilisées pour les requêtes natives avec des bases de données objet, par ex. dans db4o:
List<Document> set = db.query(new Predicate<Document>() {
public boolean match(Document candidate) {
return candidate.getSource().contains(source);
}
});
J'ai une application qui synchronise chaque jour sa base d'utilisateurs avec notre répertoire d'entreprise. Les utilisateurs sont éligibles ou non éligibles en fonction de leur statut dans l'Université. Chaque jour, le programme de provisioning passe et veille à ce que ceux qui sont supposés être éligibles soient approvisionnés dans l'application et ceux qui ne le sont pas soient désapprovisionnés (en réalité selon un algorithme de dégradation gracieuse, mais c'est sans intérêt). Samedi, je fais une mise à jour plus complète qui synchronise certaines propriétés de chaque utilisateur et s'assure qu'il dispose de l'éligibilité requise. À la fin du mois, j'effectue un traitement de facturation en fonction de l'utilisation de ce mois.
J'utilise un modèle de stratégie composable pour effectuer cette synchronisation. Le programme principal choisit essentiellement une stratégie principale en fonction du jour de la semaine (modifications de synchronisation uniquement/synchronisation de tous) et de la durée 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 je me suis dit que c'était parfaitement adapté au modèle de stratégie.
Notes principales:
Stratégie est un modèle de conception comportemental. Il est utilisé pour basculer entre les familles d’algorithmes.
Ce modèle contient une stratégie abstraite interface et plusieurs implémentations de la stratégie {concrète (algorithmes) de cette interface.
L'application utilise la stratégie interface uniquement. En fonction de certains paramètres de configuration, la stratégie concrète sera étiquetée comme interface.
Diagramme UML de wikipedia
Un exemple concret de Word: Les compagnies aériennes offrent des rabais pendant certains mois (juillet-décembre). Vous pouvez avoir un module Tarif, qui détermine les options de tarification en fonction du nombre de mois.
Regardez un exemple simple. Cet exemple peut être étendu aux applications de vente au détail en ligne, ce qui permet de bénéficier facilement d’une remise sur les articles du panier d’achat lors de journées spéciales/d’heures de plaisir.
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 modèle par source d'approvisionnement
Je sais que la question est ancienne, mais je pense avoir un autre exemple intéressant que j'ai récemment mis en œuvre.
Ceci est un exemple très pratique du modèle de stratégie utilisé dans un système de fourniture de documents.
J'avais un système de diffusion PDF qui recevait une archive contenant de nombreux documents et des métadonnées. Sur la base des métadonnées, il a décidé où placer le document; Par exemple, en fonction des données, je pourrais stocker le document dans des systèmes de stockage A
, B
ou C
, ou un mélange des trois.
Différents clients utilisaient ce système et avaient des exigences différentes en matière de gestion des erreurs et des retours en arrière en cas d'erreur: l'un voulait que le système de livraison s'arrête à la première erreur, laisse tous les documents déjà livrés dans leurs magasins, mais arrête le processus et ne livre rien d'autre ; un autre souhaitait qu'il soit annulé de B
en cas d'erreur lors du stockage dans C
, mais laisser ce qui avait déjà été livré à A
. Il est facile d'imaginer qu'un troisième ou un quatrième aura également des besoins différents.
Pour résoudre ce problème, j'ai créé une classe de distribution de base contenant la logique de distribution, ainsi que des méthodes permettant de restaurer des éléments de tous les stockages. En réalité, ces méthodes ne sont pas directement appelées par le système de livraison en cas d'erreur. Au lieu de cela, la classe utilise l’injection de dépendances pour recevoir une classe "Stratégie de traitement des erreurs/d'annulation" (basée sur le client utilisant le système), appelée en cas d'erreur, qui appelle à son tour les méthodes d'annulation si elle convient à cette stratégie.
La classe de remise elle-même rapporte ce qui se passe à la classe de stratégie (quels documents ont été remis à quels stockages et quels échecs sont survenus), et chaque fois qu'une erreur se produit, elle demande à la stratégie de continuer ou non. Si la stratégie dit "Arrêtez-la", la classe appelle la méthode "cleanUp" de la stratégie, qui utilise les informations précédemment rapportées pour décider des méthodes d'annulation à appeler à partir de la classe de livraison ou ne fait simplement rien.
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 disparaît à la première erreur et ne nettoie rien) et l'autre est la MaximizeDeliveryToAStrategy
(qui tente autant que possible de ne pas abandonner le processus et de ne jamais annuler les éléments livrés au stockage A
, mais les annulations sont remplacées par B
si la remise à C
échoue).
De ma compréhension, ceci est un exemple du modèle de stratégie. Si vous (oui, vous lisez) pensez que je me trompe, veuillez commenter ci-dessous et faites-le-moi savoir. Je suis curieux de savoir ce qui constituerait une utilisation "pure" du modèle de stratégie et quels aspects de mon implémentation enfreignent la définition. Je pense que cela semble un peu drôle parce que 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 une partie de la logique métier peut être considérée comme un algorithme, ce qui, à mon avis, est le cas).
Étant donné que la stratégie est également informée des événements au cours de l'exécution de la diffusion, elle peut également être considérée comme un Observateur , mais c'est une autre histoire.
Après quelques recherches, il semble qu’il s’agisse d’un "motif composite" (comme MVC, un motif utilisant plusieurs motifs de conception d’une manière particulière) appelé Conseiller . C'est un conseiller sur le fait de savoir si la livraison doit continuer ou non, mais c'est également un gestionnaire d'erreurs actif, car il peut annuler des tâches lorsque cela est demandé.
Quoi qu'il en soit, il s'agit d'un exemple assez complexe qui pourrait donner à votre impression que les utilisations du modèle de stratégie sont trop simples/ridicules. Cela peut être vraiment complexe et même plus applicable lorsqu'il est utilisé avec d'autres motifs.
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 simple et pratique
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 ceci 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/
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 ne pouvant utiliser qu'une seule arme à la fois. Nous avons donc le personnage comme contexte, par exemple Roi, Commandant, Chevalier, Soldat et arme comme stratégie où attack () pourrait être la méthode/algorithme dépendant des armes utilisées. Donc, si les classes d'armes concrètes étaient Sword, Axe, Arbalète, BowAndArrow, etc., elles implémenteraient toutes la méthode attack (). Je suis sûr que d'autres explications ne sont pas nécessaires.
Êtes-vous sûr que le statut d'une "commande" n'est pas un modèle d'état? J'ai l'impression qu'une commande ne sera pas traitée différemment selon son statut.
Prenons par exemple la méthode Expédier sur la commande:
order.Ship();
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 étonnant. Une seconde proche sera la série de patterns de David Cumps sur les blogs .
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.Time
pour représenter la date, mais vous souhaitez également écrire un algorithme générique qui peut aussi 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
, je voudrais simplement écrire une classe CalendarMath qui implémente les trois méthodes dans DatetimeMath, puis utiliser
OrdinalDayOfWeekCalculator odowc2 =
new OrdinalDayOfWeekCalculator(new CalendarMath());
Calendar canadianThanksgivingCal = (Calendar)odowc2.getDate(
year, Calendar.OCTOBER, Calendar.MONDAY, 2);
Nous avons dû créer une interface d'approvisionnement tiers pour une plate-forme d'entreprise avec une base de données très complexe. La soumission des données à fournir consistait en 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 de dépendances.
Le processus d’écriture de ces données était alors assez simple, continuez de sortir du haut de la file d’attente prioritaire, puis choisissez une stratégie en fonction du type de l’objet que vous extrayez.
Il y a quelques semaines, j'ai ajouté une interface Java commune mise en œuvre 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 est un schéma en étoile avec environ 10 branches ou plus. L'une des conséquences de la présence d'un objet de domaine aussi lourd est que nous avons dû créer d'autres objets de domaine représentant 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. Autrement dit, 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 CollectibleElephant
pour trier Elephant
s. Assez rapidement, mes coéquipiers ont lancé CollectibleElephant
pour effectuer des contrôles de sécurité, les filtrer au fur et à mesure de leur envoi vers l'interface graphique, etc.
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);
}
}
J'ai utilisé l'approche stratégique dans un moteur assez complexe dans une application qui est un bon exemple. Le moteur avait essentiellement pour rôle d'aller d'abord trouver une liste de personnes possédant un widget. Le second rôle consistait à déterminer quels étaient les 10 meilleurs candidats dotés d'un widget basé sur un nombre inconnu de paramètres (des éléments tels que la distance parcourue auparavant). , quantité en stock, options de livraison etc etc etc ...)
Nous avons essentiellement divisé le problème en deux stratégies, la première étant l'extraction de données, car nous savions que nous disposions de plusieurs sources de nos widgets et que nous devions être en mesure de récupérer les données et de les transformer en une structure commune.
Nous avons également réalisé que nous avions plusieurs algorithmes dont certains étaient basés sur la pondération des paramètres, d'autres étaient très bizarres et que la propreté était impossible et je ne pouvais leur rendre justice sans sortir des visios et des graphiques. sélectionner les meilleures personnes.
Notre service lui-même était très important: il définissait essentiellement les entrées, les sorties et procédait à une normalisation des données. Il utilisait également un modèle de fournisseur pour brancher les fournisseurs de données spécifiques à l'application et les fournisseurs d'algorithmes ayant utilisé 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 gabarit que nous n'avons jamais résolu.
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 lors de l'exécution. Au lieu d’implémenter directement un seul algorithme, le code reçoit des instructions d’exécution indiquant dans une famille d’algorithmes à utiliser
Dans l'application Windows Paint, vous pouvez voir un motif 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 "RedCircle", ils vous permettent de choisir le cercle et la 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 augmentera le nombre de classes avec le produit cartésien de forme et de couleur. De plus, l'interface change pour chaque implémentation.