Patrón de diseño expuesto: Patrón de estrategia



En este blog, descubriremos el Patrón de diseño de estrategia, que se utiliza para crear una familia intercambiable de algoritmos que se pueden elegir de forma dinámica.

'

Bienvenido a la primera publicación de la serie 'Design Patterns Exposed'. En esta serie vamos a descubrir cada patrón de diseño desde cero.





El simple hecho de conocer un lenguaje de programación y sus construcciones no lo convertirá en un mejor programador o desarrollador. Requiere conocimiento de patrones de diseño para crear software que funcione hoy y también en el futuro.

Muchos desarrolladores ya se han encontrado con los problemas de diseño que enfrenta ahora o que enfrentará en el futuro. Han especificado una forma estándar de abordar ese problema. Entonces, al usar Patrones de diseño, obtiene la ventaja de usar técnicas probadas.



Cada patrón de diseño sirve para resolver un tipo particular de situación; puede haber situaciones en las que se pueda utilizar más de un patrón de diseño.

La mayoría de los programadores simplemente intentan resolver el problema al que se enfrentan sin preocuparse por los patrones de diseño, el código redundante o incluso el acoplamiento estrecho. Pero los buenos programadores comienzan de manera diferente. Piensan en los requisitos de hoy, los requisitos futuros, el mantenimiento del código y la reutilización del código.

Los buenos programadores no tienen prisa por comenzar a codificar una vez que obtienen los requisitos. Se sientan y piensan en el problema de si su diseño funcionará. Si es así, si funcionará después de 6 meses, cuando los requisitos cambiarán.



Los buenos programadores toman su lápiz y papel y comienzan a diseñar sus clases y la relación entre clases. Intentan lograr un acoplamiento suelto y una alta cohesión en su diseño, mientras hacen todo esto, tienen principios orientados a objetos en su mente. No entran en el código de bajo nivel de inmediato. Para diseñar software flexible y reutilizable, debe seguir este enfoque; de ​​lo contrario, siempre se encontrará modificando el código que había escrito anteriormente.

Solo hay una cosa que es constante en la industria del software y es Cambio. Sin duda, los requisitos seguirán cambiando. Entonces, ¿cómo diseñamos el software que su código pueda adaptar fácilmente a los requisitos futuros? Para eso, debe comenzar temprano y diseñarlo de tal manera que los requisitos futuros no rompan su código anterior.

¿Cómo puedo hacer eso?

Bueno, se puede hacer siguiendo los principios de diseño y los patrones de diseño basados ​​en esos principios.

Ahora, profundicemos en la codificación y comencemos el viaje para convertirnos en un mejor programador. En esta publicación, vamos a descubrir uno de los patrones más importantes - Patrón de estrategia .

Cuando digo lo más importante, reflexiona sobre el problema común que se resuelve mediante el Patrón de estrategia.

¿Qué es el patrón de estrategia?

Aquí está la definición directamente del libro 'Gang of Four': 'El patrón de estrategia se utiliza para crear una familia intercambiable de algoritmos a partir de los cuales se elige el proceso requerido en tiempo de ejecución.”.

En caso de que seasno puedo entender, no te preocupes, te lo vamos a explicar en unmas simplecaminopara que túentender.

Primero entendamos el problema y luego veremos cómo Strategy Pattern puede resolverlo.

En el diagrama UML anterior, tenemos la clase abstracta Animal y dos clases concretas, Perro y Pájaro, que se extienden desde la superclase Animal.

Así que definamos una clase abstracta Animal y dos clases concretas, Perro y Pájaro.

cómo configurar classpath en linux

¿Qué opinas del diseño anterior? Hay un gran error en nuestro diseño.

Todos los animales no pueden volar, como en el caso anterior un perro no puede volar. Pero todavía tiene un comportamiento de 'volar'.

Cometimos un error al escribir el método abstracto fly () dentro de la clase Animal. Este diseño obligará a cada subclase Perro, Pájaro, Pingüino, Cocodrilo, Ganso, etc. a implementar el método fly ().

Deberíamos haber entendido que volar es una habilidad que no todos los animales tendrán. Al proporcionar el método fly () en la clase abstracta Animal, hemos establecido la capacidad de vuelo en todas las subclases, lo que no es correcto para todas las subclases de animales.

Podría pensar cuál es el problema al implementar el método fly en las subclases. Aunque puede implementar el método fly () en las subclases de animales no voladores para imprimir simplemente 'No puedo volar'. Pero el problema es que todavía está dando el comportamiento de mosca a los animales que no vuelan. Esto no es correcto.

¿Qué se siente al llamar a dog.fly () o crocodile.fly ().

Entonces, ahora hemos entendido que nuestro diseño no es correcto y debemos eliminar el método fly () de la subclase Animal.

¿Cuál es la otra forma de diseñar nuestras clases de manera que nuestro diseño no obligue a todas las subclases de animales a tener comportamiento de mosca?

Una solución que viene inmediatamente a la mente es que podemos hacer una interfaz de vuelo con el método de volar y solo los animales que pueden volar implementarán esa interfaz de vuelo. De esta forma, no exigiremos que todas las subclases de animales definan el comportamiento de una mosca. Así que codifiquemos este enfoque de diseño.

Ahora, nuestra clase Animal se verá como el código siguiente después de eliminar el método fly de la clase Animal.

Ahora definamos la interfaz Flying

Ahora, la clase de perro cambiarácomoel código siguiente y no necesita tener comportamiento de vuelo.

Veamos algunas de nuestras subclases de animales que tendrán comportamiento de vuelo.

Hemos resuelto nuestro problema anterior, pero nos metimos en un nuevo problema y es la 'duplicación de código'.

Digamos, vamos a tener 100 diferentes subclases de animales voladores. Tenemos que duplicar el código para el comportamiento de vuelo ya que la interfaz de vuelo no puede proporcionar ninguna implementación para el comportamiento de vuelo, y luego, si queremos cambiar la implementación del método fly () en cualquier subclase, tendremos que abrir esa clase y cambiar el código, cual es malo. Nos falta algo grande y, es decir, no podemos cambiar el comportamiento de vuelo de una clase en tiempo de ejecución.

Pero no se preocupe, el Patrón de estrategia está ahí para sacarlo de este problema.

Así que refactoricemos nuestro código para usar Strategy Pattern.

La interfaz de vuelo seguirá siendo la misma. Ahora, en lugar de que cada subclase de vuelo implemente la interfaz de vuelo en sí, vamos a definir clases concretas separadas que implementarán un comportamiento de vuelo diferente. Veamos cómo hacer eso.

Entonces, cómo funciona todo, veamos TestClass

Al usar el Patrón de estrategia, ahora podemos cambiar el comportamiento de vuelo de cualquier animal en tiempo de ejecución y eso sin obligar a ninguna subclase a especificar el comportamiento de vuelo en sí.

¿Cuándo usar el patrón de estrategia?

Cuando desee poder cambiar el comportamiento en tiempo de ejecución de forma dinámica.

Para asegurarse de que comprende claramente el patrón de estrategia, tomemos otro ejemplo.

En la clase de Empleado anterior, establecemos la paga del empleado según su designación. Si un empleado es un 'pasante', estamos agregando un bono del 10% en el salario básico para calcular el salario real.

Si un empleado es un 'Desarrollador Web', estamos agregando un bono del 20% en el salario básico para calcular el pago real y se sigue un proceso similar para otros tipos de empleados. Aunque nuestro algoritmo para calcular el pago real es muy simple para que sea más fácil de entender, la mayoría de las veces incluye muchas comparaciones y cálculos.

Entonces, ¿qué pasa con el código de clase de empleado?

Bueno, el código para calcular el pago (getPay ()) es estático. Supongamos que quiero cambiar la bonificación para 'Pasante' del 10% al 14%. Tendré que abrir el código de la clase de empleado y cambiarlo.

Y otro problema es que no puedo cambiar el algoritmo de pago de un empleado en tiempo de ejecución. Entonces, ¿cómo hacer eso? El patrón de estrategia se utiliza específicamente para manejar este tipo de problema.

Refactoricemos el código para usar el patrón de estrategia.

Voy a definir varios algoritmos para calcular el pago. Entonces podré usar cualquiera de estos algoritmos para calcular el pago en tiempo de ejecución.

Ahora, veamos cómo va a cambiar la clase de empleado.

Nota: Eliminé la lógica de cálculo de pago de la clase Employee y creé un método de PayAlgorithm () establecido a través del cual estableceré el PayAlgorithm que quiero usar para el cálculo de pago.

Esto me dará la flexibilidad de calcular el pago especificando cualquier algoritmo de pago dinámicamente en tiempo de ejecución. Además, tenga en cuenta que más adelante, si tengo que cambiar la lógica de cálculo de pago, puedo crear un nuevo algoritmo de pago y usarlo para calcular el pago. No necesito cambiar el código anterior, ¿no es genial?

Así que veámoslo funcionando.

Espero que haya entendido muy bien el Patrón de estrategia. La mejor forma de aprender algo es practicando.

En caso de que tenga alguna consulta relacionada con el Patrón de estrategia o cualquier otro Patrón, deje sus consultas a continuación.

Esté atento a la próxima publicación, donde descubriremos uno de los patrones de diseño más populares, el patrón de fábrica.

Hasta entonces, puede descargar el código, jugar con él y asegurarse de cimentar el Patrón de estrategia en su cabeza.

Tienes una pregunta para nosotros? Menciónalos en la sección de comentarios y nos pondremos en contacto contigo.

Artículos Relacionados: