template strategy pattern patrones patron observer method estrategia ejemplos diseño design-patterns encapsulation strategy-pattern command-pattern

design-patterns - patrones - strategy design pattern



Usando un patrón de estrategia y un patrón de comando (7)

Contestando una pregunta muy vieja. (¿Alguien está viendo las últimas respuestas en lugar de las más votadas?)

Es una confusión válida debido a las similitudes. Los patrones de Estrategia y Comando utilizan la encapsulación . Pero eso no los hace iguales.

La diferencia clave es entender lo que está encapsulado. El principio de OO, ambos patrones dependen de, encapsula lo que varía .

En el caso de la estrategia, lo que varía es el algoritmo . Por ejemplo, un objeto de estrategia sabe cómo exportar a un archivo XML, mientras que el otro lo envía a, por ejemplo, JSON. Diferentes algoritmos se mantienen ( encapsulados ) en diferentes clases. Es tan simple como eso.

En caso de comando, lo que varía es la solicitud en sí. La solicitud puede provenir del File Menu > Delete o hacer Right Click > Context Menu > Delete File Menu > Delete Right Click > Context Menu > Delete o Just Delete Button pressed . Los tres casos pueden generar 3 objetos de comando del mismo tipo. Estos objetos de comando solo representan 3 solicitudes de eliminación; no algoritmo de eliminación. Como las solicitudes ahora son un montón de objetos, podríamos gestionarlas fácilmente. De repente, se vuelve trivial proporcionar funcionalidades como deshacer o rehacer.

No importa cómo el comando implementa la lógica solicitada. Al ejecutar execute (), puede implementar un algoritmo para activar la eliminación o incluso puede delegarlo a otros objetos, incluso puede delegar en una estrategia. Es solo el detalle de implementación del patrón de comando. Es por eso que recibe el nombre de comando, aunque no es una forma educada de solicitarlo : -)

Contraste con la estrategia; este patrón solo se refiere a la lógica real que se ejecuta. Si hacemos eso, ayuda a lograr diferentes combinaciones de comportamientos con un conjunto mínimo de clases, evitando así la explosión de clase.

Creo que Command nos ayuda a ampliar nuestra comprensión de la encapsulación mientras que Strategy proporciona un uso natural de la encapsulación y el polimorfismo.

Ambos patrones de diseño encapsulan un algoritmo y desacoplan detalles de implementación de sus clases de llamada. La única diferencia que puedo discernir es que el patrón de Estrategia toma los parámetros para la ejecución, mientras que el patrón de Comando no.

Me parece que el patrón de comando requiere que toda la información para la ejecución esté disponible cuando se crea, y es capaz de retrasar su llamada (quizás como parte de un script).

¿Qué determinaciones guían si usar un patrón u otro?


En mi opinión, podría estar equivocado, pero trato el command como función-para-ejecutar, o reacción. Debe haber al menos dos jugadores: el que solicita la acción y el que ejecuta la acción. GUI es un ejemplo típico de patrón de comando:

  • Todos los botones en la barra de herramientas de la aplicación están asociados con alguna acción.
  • Button es el ejecutor en este caso.
  • La acción es el comando en este caso.

El comando generalmente está limitado a algún ámbito o área comercial, pero no es necesario: puede tener comandos que emitan una factura, inicien un cohete o eliminen un archivo que implementa la misma interfaz (por ejemplo, el método single execute() ) dentro de una aplicación. A menudo, los comandos son autónomos, por lo que no necesitan nada del ejecutor para procesar la tarea que se proponen (toda la información necesaria se proporciona en tiempo de construcción), a veces los comandos son sensibles al contexto y deberían ser capaces de descubrir este contexto. (El comando de retroceso debe conocer la posición de intercalación en el texto para eliminar correctamente el carácter anterior; el comando Revertir debería descubrir la transacción actual para deshacer; ...).

La strategy es un poco diferente: está más ligada a algún área. La estrategia puede definir una regla para formatear una fecha (en UTC? ¿Específico de la configuración regional?) (Estrategia "formateador de fechas") o para calcular un cuadrado para una figura geométrica (estrategia de "calculadora cuadrada"). Las estrategias son, en este sentido, objetos de peso mosca, que toman algo como entrada ("fecha", "figura", ...) y toman una decisión sobre la base. Tal vez no sea el mejor, pero un buen ejemplo de estrategia es uno conectado con la interfaz javax.xml.transform.Source : dependiendo de si el objeto pasado es DOMSource o SAXSource o StreamSource la estrategia (= transformador XSLT en este caso) aplicará diferentes reglas para procesalo. La implementación puede ser un simple switch o involucrar un patrón de Cadena de responsabilidad .

Pero, de hecho, hay algo en común entre estos dos patrones: los comandos y las estrategias encapsulan algoritmos dentro de la misma área semántica.


Incluyo una tabla de jerarquía de encapsulación de varios de los patrones de diseño de GoF para ayudar a explicar las diferencias entre estos dos patrones. Con suerte, ilustra mejor lo que encapsula cada uno, por lo que mi explicación tiene más sentido.

En primer lugar, la jerarquía enumera el alcance para el cual un patrón dado es aplicable, o el patrón apropiado para usar para encapsular algún nivel de detalle, dependiendo del lado de la tabla en el que comiences.

Como se puede ver en la tabla, un objeto Patrón de estrategia oculta detalles de la implementación de un algoritmo, por lo que el uso de un objeto de estrategia diferente realizará la misma funcionalidad pero de una manera diferente. Cada objeto de estrategia puede optimizarse para un factor particular u operar en algún otro parámetro; y, a través del uso de una interfaz común, el contexto puede funcionar con seguridad con cualquiera de los dos.

El patrón de comando encapsula un nivel de detalle mucho más pequeño que un algoritmo. Codifica los detalles necesarios para enviar un mensaje a un objeto: receptor, selector y argumentos. El beneficio de objetivar una parte tan pequeña de la ejecución del proceso es que dichos mensajes se pueden invocar a lo largo de diferentes puntos de tiempo o ubicación de una manera general sin tener que codificar sus detalles. Permite invocar los mensajes una o más veces, o pasarlos a diferentes partes del sistema o sistemas múltiples sin que se requiera conocer los detalles de una invocación específica antes de la ejecución.

Como es típico para los patrones de diseño, no requieren que todas las implementaciones sean idénticas en detalle para llevar el nombre del patrón. Los detalles pueden variar en la implementación y en qué datos se codifican en los argumentos de objeto versus método.


La forma en que lo veo es que tienes múltiples formas de hacer lo mismo, cada una de ellas es una estrategia, y algo en tiempo de ejecución determina qué estrategia se ejecutará.

Tal vez primero intente StrategyOne, si los resultados no son lo suficientemente buenos, intente StrategyTwo ...

Los comandos están ligados a cosas distintas que deben suceder, como TryToWalkAcrossTheRoomCommand. Este comando se disparará cada vez que algún objeto intente cruzar la habitación, pero dentro de él podría intentar con StrategyOne y StrategyTwo intentar cruzar la habitación.

marca


Las estrategias encapsulan algoritmos. Los comandos separan al emisor del receptor de una solicitud, convierten una solicitud en un objeto.

Si es un algoritmo, cómo se hará algo, usa una Estrategia. Si necesita separar la llamada de un método de su ejecución, use un comando. Los comandos se utilizan a menudo cuando se ponen en cola los mensajes para su uso posterior, como una tarea o una transacción.


Para mí, la diferencia es la intención. Las implementaciones de ambos patrones son bastante similares, pero tienen diferentes propósitos:

  • Para una estrategia, el componente que usa el objeto sabe lo que hace el objeto (y lo usará para realizar una parte de su propio trabajo), pero no le importa cómo lo hace.

  • Para un comando, el componente que utiliza el objeto no sabe qué hace el comando ni cómo lo hace, solo sabe cómo invocarlo. La tarea del que llama es simplemente ejecutar el comando: el procesamiento llevado a cabo por el comando no forma parte del trabajo principal del llamador.

Esta es la diferencia: ¿el objeto que utiliza el componente realmente sabe o se preocupa por lo que hace el componente? La mayoría de las veces esto se puede determinar en función de si el objeto patrón devuelve un valor a su invocador. Si el invocador se preocupa por lo que hace el objeto patrón, probablemente querrá que devuelva algo y será una estrategia. Si no le importa el valor devuelto, probablemente sea un Comando (tenga en cuenta que algo así como un Java Callable sigue siendo un Comando porque, aunque devuelve un valor, a la persona que llama no le importa el valor, simplemente lo restituye). a lo que originalmente suministró el Comando).


Mando:

Componentes básicos:

  1. Command declara una interfaz para comandos abstractos como execute()
  2. El receptor sabe cómo ejecutar un comando en particular
  3. Invoker tiene ConcreteCommand , que debe ser ejecutado
  4. El cliente crea ConcreteCommand y asigna Receiver
  5. ConcreteCommand define el enlace entre Comando y Receptor

Flujo de trabajo:

Llamadas de cliente Invoker => Llamadas de Invoker ConcreteCommand => ConcreteCommand llama al método Receiver , que implementa el método abstracto Command .

Ventaja : el cliente no se ve afectado por los cambios en Comando y Receptor. Invoker proporciona un acoplamiento flexible entre el Cliente y el Receptor. Puede ejecutar múltiples comandos con el mismo Invoker.

El patrón de comando le permite ejecutar un comando en diferentes Receptores utilizando el mismo Invoker . Invoker desconoce el tipo de receptor

Para una mejor comprensión de los conceptos, eche un vistazo a este article de JournalDev de Pankaj Kumar y al article dzone de James Sugrue además del enlace de Wikipedia.

Puedes usar el patrón Command para

  1. Desacoplar el invocador y el receptor de comando

  2. Implementar el mecanismo de devolución de llamada

  3. Implementar la funcionalidad de deshacer y rehacer

  4. Mantener un historial de comandos

java.lang.Thread es una buena implementación del patrón Command . Puede tratar Thread como invocador y clase implementando Runnable como ConcreteCommonad / Receiver y el método run() como Command .

La versión de deshacer / rehacer del patrón de comando se puede leer en el article Theodore Norvell

Estrategia:

El patrón de estrategia es muy simple de entender. Use este patrón cuando

Tiene múltiples implementaciones para un algoritmo y la implementación del algoritmo puede cambiar en tiempo de ejecución dependiendo de las condiciones particulares .

Tome un ejemplo del componente Tarifa del sistema de reservas de aerolíneas

A las aerolíneas les gustaría ofrecer diferentes tarifas durante diferentes períodos de tiempo: máximo y mínimo. Durante los días pico de viaje, le gustaría estimular la demanda ofreciendo atractivos descuentos.

Puntos clave del patrón de estrategia :

  1. Es un patrón de comportamiento
  2. Se basa en la delegación
  3. Cambia las agallas del objeto modificando el comportamiento del método
  4. Se usa para cambiar entre familia de algoritmos
  5. Cambia el comportamiento del objeto en tiempo de ejecución

Publicaciones relacionadas con ejemplos de código:

Uso del patrón de diseño de comando

Ejemplo del mundo real del patrón de estrategia