Utilisation pratique du modèle de stratégie

L'utilisation de modèles (ou de modèles) dans la programmation orientée objet découle du désir de rendre le code plus simple, plus fiable et de ne pas réinventer la roue, ainsi que de permettre aux organisateurs de travailler efficacement avec différents niveaux de formation, ce qui leur donne une base unique pour comprendre le code source dans le cadre conceptuel de la logique métier. applications. Cela signifie que l'apprentissage des modèles de conception est une étape clé dans le développement professionnel d'un programmeur.

Comment étudier les modèles de conception? Il y a deux approches: ennuyeuse et intelligible (vous aimez ma classification?). Une approche ennuyeuse implique l'étude académique d'une liste de modèles à l'aide d'exemples abstraits. Personnellement, je préfère le contraire - une approche intelligible, lorsque la définition de la tâche à un niveau de formulation relativement élevé vous permet de choisir des modèles de conception. Bien que vous puissiez combiner les deux approches.

Alors allons-y?

Le modèle de stratégie fait référence à un groupe de modèles de comportement.

Brève définition du modèle de stratégie


Le modèle sert à basculer entre une famille d'algorithmes lorsqu'un objet change de comportement en fonction d'un changement de son état interne.

Exemples pratiques d'application du modèle de stratégie


  • Tri: nous voulons trier ces nombres, mais nous ne savons pas si nous utiliserons BrickSort, BubbleSort ou tout autre tri. Par exemple, vous avez un site Web sur lequel une page affiche des éléments basés sur la popularité. Cependant, beaucoup de choses peuvent être «populaires» (la plupart des vues, la plupart des abonnés, la date de création, la plupart des activités, le moins de commentaires). Dans le cas où la direction ne sait pas encore exactement comment passer une commande et peut vouloir expérimenter différentes commandes à une date ultérieure, vous créez une interface (IOrderAlgorithm ou autre) avec la méthode order et autorisez l'objet Orderer à déléguer l'ordre de la mise en œuvre concrète de l'interface IOrderAlgorithm . Vous pouvez créer CommentOrderer, ActivityOrderer, etc., et simplement les désactiver lorsque de nouvelles exigences apparaissent.
  • Traitement d'une file d'attente à partir d'objets hétérogènes (traitement de la file d'attente et sauvegarde des données): un exemple serait un système proxy qui accumule des objets de différentes sources de données, puis après avoir extrait un objet de la file d'attente et l'avoir enregistré, il est déterminé par la stratégie de sélection basée sur les propriétés de cet objet.
  • Validation Nous devons vérifier les éléments conformément à la "règle", mais on ne sait pas encore ce que sera cette règle, et nous pouvons en penser de nouveaux.
  • Authentification: sélectionnez une stratégie d'authentification entre les schémas de base, Digest, OpenID et OAuth.

Voici un exemple:

interface AuthStrategy {
    auth(): void;
}
class Auth0 implements AuthStrategy {
    auth() {
        log('Authenticating using Auth0 Strategy')
    }
}
class Basic implements AuthStrategy {
    auth() {
        log('Authenticating using Basic Strategy')
    }
}
class OpenID implements AuthStrategy {
    auth() {
        log('Authenticating using OpenID Strategy')
    }
}

class AuthProgram {
    private _strategy: AuthStrategy
    use(strategy: AuthStrategy) {
        this._strategy = strategy
        return this
    }
    authenticate() {
        if(this._strategy == null) {
            log("No Authentication Strategy set.")
        }
        this._strategy.auth()
    }
    route(path: string, strategy: AuthStrategy) {
        this._strategy = strategy
        this.authenticate()
        return this
    }
}

  • (games): — , , , , , , , . , , , , . «», «», «» Attack() . , «», «», «», « » Attack ().
  • (storing information): , , -. , PDF, , . , ; , , A, B C, . PDF , / PDF. , , , , , , B C, , A. , . PDF, , , . . Dependency Injection « / » ( , ), , , , , . , ( , ), , , , . « », «cleanUp» , , , , .
  • (outputting): X , CSV, XML, JSON .
  • (invoicing): - , , - .
  • (navigation): .
  • (logging): Log4Net Log4j , Appenders, Layouts, and Filters.
  • Cryptage: pour les petits fichiers, vous pouvez utiliser la stratégie en mémoire lorsque le fichier entier est lu et stocké en mémoire (par exemple, pour les fichiers <1 Go). Pour les fichiers volumineux, vous pouvez utiliser une stratégie différente 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.

Voici un exemple:

//   ""
interface  Cipher  {
     public void performAction();
}

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

class SwaptToDiskCipher implements Cipher { 
         public void performAction() {
             //     .... 
         }

}

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

  • Editeur graphique: par exemple, dans l'application Windows Paint, il existe une implémentation d'un modèle de stratégie dans lequel vous pouvez sélectionner indépendamment la forme et la couleur dans différentes sections. Ici, la forme et la couleur sont des algorithmes qui peuvent être modifiés lors de l'exécution.

Shape redCircle = new RedCircle(); //    «»
Shaped redCircle = new Shape("red","circle"); //   «»

SOLIDE et mise en œuvre du modèle de stratégie


Quel est le principal problème résolu par le modèle "Stratégie"? En fait, il s'agit d'un remplacement pour le code plat IF .... QUE ... ... sur son implémentation d'objet.

Exemple de code plat sale (faux):

class Document {...}
class Printer {
    print(doc: Document, printStyle: Number) {
        if(printStyle == 0 /*   */) {
            // ...
        }
        if(printStyle == 1 /*  */) {
            // ...            
        }
        if(printStyle == 2 /*     */) {
            // ...
        }
        if(printStyle == 3 /*     */) {
            // ...            
        }
        if(printStyle == 4 /*     */) {
            // ...
        }
        // ...
    }
}

Un exemple du même code avec le modèle "Stratégie" (correctement):

class Document {...}
interface PrintingStrategy {
    printStrategy(d: Document): void;
}
class ColorPrintingStrategy implements PrintingStrategy {
    printStrategy(doc: Document) {
        log(" ")
        // ...
    }
}
class InvertedColorPrintingStrategy implements PrintingStrategy {
    printStrategy(doc: Document) {
        log("  ")
        // ...
    }
}
class Printer {
    private printingStrategy: PrintingStrategy
    print(doc: Document) {
        this.printingStrategy.printStrategy(doc)
    }
}

Voici un autre exemple de la mise en œuvre correcte du modèle de stratégie basé sur SOLID.

//  /
interface LockOpenStrategy {
    open();
    lock();
}
//      
class RetinaScannerLockOpenStrategy implements LockOpenStrategy {
    open() {
        //...
    }
    lock() {
        //...
    }
}

//       
class KeypadLockOpenStrategy implements LockOpenStrategy {
    open() {
        if(password != ""){
            log("Entry Denied")
            return
        }
        //...
    }
    lock() {
        //...
    }
}
//        .
abstract class Door {
    public lockOpenStrategy: LockOpenStrategy
}
//   .
class GlassDoor extends Door {}
//    .
class MetalDoor extends Door {}
//       .
class DoorAdapter {
    openDoor(d: Door) {
        d.lockOpenStrategy.open()
    }
}

Vous trouverez ci-dessous l'encodage réel de la logique.

var glassDoor = new GlassDoor(); //   
glassDoor.lockOpenStrategy = new RetinaScannerLockOpenStrategy(); //         
var metalDoor = new MetalDoor(); //     
metalDoor.lockOpenStrategy = new KeypadLockOpenStrategy(); //      .
var door1 = new DoorAdapter().openDoor(glassDoor); //    . 
var door2  = new DoorAdapter().openDoor(metalDoor); //    . 

Comme vous pouvez le voir ci-dessus, il s'agit d'un code entièrement orienté objet qui exclut le style procédural IF .... AUTRE ....... ou COMMUTATEUR ... CAS ...

Soit dit en passant, pourquoi avons-nous utilisé la classe d'adaptateur? La porte elle-même ne s'ouvre pas, elle s'ouvre toujours avec quelque chose d'une part, et d'autre part, il peut y avoir des événements précédant l'ouverture de la porte ou à la fin de son ouverture, par exemple BeforeOpen () et AfterOpen (), peuvent également être liés à adaptateur.

Refactoring et modèle de stratégie


Le modèle de stratégie doit être utilisé lorsque vous commencez à remarquer des algorithmes répétitifs, mais dans différentes variantes. Ainsi, il est nécessaire de diviser les algorithmes en classes et de les remplir au besoin dans votre programme.

De plus, si vous remarquez des instructions conditionnelles en double autour d'un algorithme frère.
Lorsque la plupart des classes ont un comportement associé. Et puis vous devez le sélectionner et les déplacer vers des classes distinctes.

J'espère que cette sélection d'exemples vous aidera à utiliser le modèle "Stratégie" de manière appropriée.
Je serai heureux si vous pouvez donner plus d'exemples de ce modèle dans les commentaires.

Bon codage, amis et collègues!

Source: https://habr.com/ru/post/undefined/


All Articles