Uso práctico de la plantilla de estrategia.

El uso de plantillas (o patrones) en la programación orientada a objetos surge del deseo de hacer que el código sea más simple, más confiable y de no reinventar la rueda, así como de permitir que los organizadores trabajen juntos de manera efectiva con diferentes niveles de capacitación, dándoles una base única para comprender el código fuente en el marco conceptual de la lógica empresarial. aplicaciones. Esto significa que aprender patrones de diseño es un paso clave en el desarrollo profesional de un programador.

¿Cómo estudiar patrones de diseño? Hay dos enfoques: aburrido e inteligible (¿Te gusta mi clasificación?). Un enfoque aburrido implica el estudio académico de una lista de patrones usando ejemplos abstractos. Personalmente, prefiero lo contrario: un enfoque inteligible, cuando establecer la tarea en un nivel relativamente alto de formulación le permite elegir patrones de diseño. Aunque puedes combinar ambos enfoques.

¿Entonces vamos?

La plantilla de estrategia se refiere a un grupo de plantillas de comportamiento.

Breve definición de la plantilla de estrategia


La plantilla sirve para cambiar entre una familia de algoritmos cuando un objeto cambia su comportamiento en función de un cambio en su estado interno.

Ejemplos prácticos de aplicación de la plantilla de estrategia.


  • Clasificación: queremos clasificar estos números, pero no sabemos si usaremos BrickSort, BubbleSort o cualquier otra clasificación. Por ejemplo, tiene un sitio web en el que una página muestra elementos basados ​​en popularidad. Sin embargo, muchas cosas pueden ser "populares" (la mayoría de las vistas, la mayoría de los suscriptores, la fecha de creación, la mayor actividad, la menor cantidad de comentarios). En caso de que la administración aún no sepa exactamente cómo hacer un pedido, y desee experimentar con diferentes pedidos en una fecha posterior, cree una interfaz (IOrderAlgorithm u otra cosa) con el método de pedido y permita que el objeto Orderer delegue el orden de la implementación concreta de la interfaz IOrderAlgorithm . Puede crear CommentOrderer, ActivityOrderer, etc., y simplemente desactivarlos cuando aparezcan nuevos requisitos.
  • Procesar una cola a partir de objetos heterogéneos (procesamiento de la cola y guardar datos): un ejemplo sería un sistema proxy que acumula objetos de diferentes fuentes de datos, luego, después de extraer un objeto de la cola y luego guardarlo, está determinado por la estrategia de selección basada en las propiedades de este objeto.
  • Validación Necesitamos verificar los elementos de acuerdo con la "Alguna Regla", pero aún no está claro cuál será esta regla, y podemos pensar en otros nuevos.
  • Autenticación: Seleccione una estrategia de autenticación entre los esquemas Básico, Digest, OpenID, OAuth.

Aquí hay un ejemplo:

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.
  • Cifrado: para archivos pequeños, puede usar la estrategia en memoria cuando todo el archivo se lee y se almacena en la memoria (por ejemplo, para archivos <1 GB). Para archivos grandes, puede usar una estrategia diferente en la que partes del archivo se leen en la memoria y los resultados parcialmente encriptados se almacenan en archivos tmp. Estas pueden ser dos estrategias diferentes para la misma tarea.

Aquí hay un ejemplo:

//   ""
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();

  • Editor gráfico: por ejemplo, en la aplicación Windows Paint hay una implementación de una plantilla de estrategia en la que puede seleccionar independientemente la forma y el color en diferentes secciones. Aquí, la forma y el color son algoritmos que se pueden cambiar en tiempo de ejecución.

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

SÓLIDO e implementación de la plantilla de estrategia


¿Cuál es el principal problema que resuelve la plantilla "Estrategia"? De hecho, este es un reemplazo para el código plano SI ... ESO ... ... en su implementación de objetos.

Ejemplo de código plano sucio (incorrecto):

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 ejemplo del mismo código con la plantilla "Estrategia" (correctamente):

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

Aquí hay otro ejemplo de la implementación correcta de la plantilla de Estrategia basada en 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()
    }
}

A continuación se muestra la codificación real de la lógica.

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

Como puede ver arriba, este es un código totalmente orientado a objetos que excluye el estilo de procedimiento IF ... OTROS ....... o INTERRUPTOR ... CASO ...

Por cierto, ¿por qué usamos la clase de adaptador? La puerta en sí no se abrirá, siempre se abre con algo, por un lado, y por otro puede haber algunos eventos que preceden a la apertura de la puerta o al finalizar su apertura, por ejemplo BeforeOpen () y AfterOpen (), también se pueden vincular a adaptador.

Plantilla de refactorización y estrategia


La plantilla "Estrategia" se debe usar cuando comience a notar algoritmos repetitivos, pero en diferentes variaciones. Por lo tanto, es necesario dividir los algoritmos en clases y completarlos según sea necesario en su programa.

Además, si observa declaraciones condicionales duplicadas alrededor de un algoritmo hermano.
Cuando la mayoría de las clases tienen un comportamiento asociado. Y luego debe seleccionarlo y moverlos a clases separadas.

Espero que esta selección de ejemplos lo ayude a usar la plantilla "Estrategia" de manera adecuada.
Me alegrará si puede dar más ejemplos de esta plantilla en los comentarios.

Feliz codificación, amigos y colegas!

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


All Articles