He estado leyendo sobre el director de OCP y cómo usar el patrón de estrategia para lograrlo.
Iba a intentar explicar esto a un par de personas, pero el único ejemplo en el que puedo pensar es en el uso de diferentes clases de validación basadas en el estado de una "orden".
He leído un par de artículos en línea, pero estos no suelen describir una razón real para usar la estrategia, como generar informes / facturas / validación, etc.
¿Hay ejemplos del mundo real en los que crea que un patrón de estrategia es común?
fuente
Cipher C =null; if (file.size() <= 2048) { C = new InMemoryCipherStrategy(); } else { c= SwaptToDiskCipher (); }
CipherFactory
puede confundir a quienes no están familiarizados con el patrón de estrategia.Una vez más, una publicación antigua, pero todavía aparece en las búsquedas, así que agregaré dos ejemplos más (el código está en C #). Me encanta el patrón de estrategia, ya que me ha salvado el trasero muchas veces cuando los gerentes de proyecto dicen: "Queremos que la aplicación haga 'X', pero 'X' aún no está claro y puede cambiar en un futuro cercano. " Este video que explica el patrón de estrategia , usa StarCraft como ejemplo.
Cosas que entran en esta categoría:
Clasificación: Queremos ordenar estos números, pero no sabemos si vamos a usar BrickSort, BubbleSort o alguna otra clasificación.
Validación: Necesitamos verificar los elementos de acuerdo con "Alguna regla", pero aún no está claro cuál será esa regla y podemos pensar en otras nuevas.
Juegos: Queremos que el jugador camine o corra cuando se mueva, pero tal vez en el futuro, también debería poder nadar, volar, teletransportarse, excavar bajo tierra, etc.
Almacenamiento de información: queremos que la aplicación almacene información en la base de datos, pero más adelante es posible que deba poder guardar un archivo o realizar una llamada web.
Salida: Necesitamos generar X como una cadena simple, pero más tarde puede ser un CSV, XML, JSON, etc.
Ejemplos
Tengo un proyecto donde los usuarios pueden asignar productos a personas en una base de datos. Esta asignación de un producto a una persona tiene un estado que es "Aprobado" o "Rechazado", que depende de algunas reglas comerciales. Por ejemplo: si un usuario asigna un producto a una persona con cierta edad, su estado debe ser rechazado; Si la diferencia entre dos campos en el elemento es mayor que 50, su estado se rechaza, etc.
Ahora, en el momento del desarrollo, estas reglas de negocio aún no están completamente claras y podrían surgir nuevas reglas en cualquier momento. El poder del patrón de estrategia es que hice un RuleAgent, al que se le da una lista de IRules.
En el momento de asignar un producto a una persona, creo un RuleAgent, le doy una lista de reglas (que implementan IRule) y le pido que valide una asignación. Pasará por todas sus reglas. Lo cual, debido a que todos implementan la misma interfaz, todos tienen el
IsApproved
método y devuelven falso si alguno de ellos devuelve falso.Ahora, cuando, por ejemplo, el gerente aparece de repente y dice, también debemos rechazar todas las asignaciones a los pasantes, o todas las asignaciones a las personas que trabajan horas extras ... Usted crea nuevas clases como esta:
Verá que no tiene que seguir agregando o eliminando declaraciones if o código, simplemente cree una nueva clase de reglas que implemente la interfaz IRUle y cámbielas cuando sea necesario.
Otro gran ejemplo: la serie de videos de Scott Allen en http://www.asp.net/mvc/pluralsight donde usa el patrón de estrategia en la parte de prueba unitaria de la aplicación
Construye un sitio web que tiene una página que muestra elementos basados en la popularidad. Sin embargo, "Popular" puede ser muchas cosas (la mayoría de las vistas, la mayoría de los suscriptores, la fecha de creación, la mayor cantidad de actividad, la menor cantidad de comentarios, etc.) y, en caso de que la administración aún no sepa exactamente cómo ordenar, es posible que desee experimentar con diferentes pedidos en una fecha posterior. Usted crea una interfaz (IOrderAlgorithm o algo así) con un método de orden, y deja que un objeto Orderer delegue la ordenación a una implementación concreta de la interfaz IOrderAlgorithm. Puede crear un "CommentOrderer", "ActivityOrderer", etc. Y simplemente cambiarlos cuando surjan nuevos requisitos.
fuente
InternRule
ahora, pero ¿cómo lo estamos activandoOvertimeRule
? ¿Cómo nos aseguramos de que cualquier lógica llamadaOvertimeRule.IsApproved
ahora también llameInternRule.IsApproved
?Notas clave:
La estrategia es un patrón de diseño conductual. Se utiliza para cambiar entre familias de algoritmos.
Este patrón contiene una interfaz de estrategia abstracta y muchas implementaciones de estrategias concretas ( algoritmos ) de esa interfaz.
La aplicación utiliza únicamente la interfaz de estrategia . Dependiendo de algún parámetro de configuración, la estrategia concreta se etiquetará como interfaz .
Diagrama UML de wikipedia
Un ejemplo de palabra real: aerolíneas que ofrecen descuentos durante algunos meses (julio-diciembre) . Puede tener un módulo de tarifa , que decide las opciones de precios según el número de mes.
Eche un vistazo a un ejemplo sencillo. Este ejemplo puede extenderse a aplicaciones de venta minorista en línea, que ofrecen descuentos en artículos del carrito de compras en días especiales / horas felices fácilmente.
salida:
Artículos útiles:
patrón de estrategia de dzone
patrón de estrategia por sourcemaking
fuente
Puedo pensar en varios ejemplos bastante simples:
Compresión de datos. Es posible que tenga una interfaz ICompressor cuyo único método se parezca a esto:
byte [] comprimir (byte [] entrada);
Sus clases de compresión concretas pueden ser cosas como RunLengthCompression, DeflateCompression, etc.
fuente
Un uso común del patrón de estrategia es definir estrategias de clasificación personalizadas (en lenguajes sin funciones de orden superior), por ejemplo, para ordenar una lista de cadenas por longitud en Java, pasando una clase interna anónima (una implementación de la interfaz de la estrategia):
De manera similar, se pueden utilizar estrategias para consultas nativas con bases de datos de objetos, por ejemplo, en db4o:
fuente
Tengo una aplicación que sincroniza su base de usuarios cada día con nuestro directorio empresarial. Los usuarios son elegibles o no en función de su estado en la Universidad. Todos los días, el programa de aprovisionamiento se ejecuta y se asegura de que aquellos que se supone que son elegibles sean aprovisionados en la aplicación y aquellos que no lo sean se desaprovisionen (en realidad, de acuerdo con un elegante algoritmo de degradación, pero eso no viene al caso). El sábado hago una actualización más exhaustiva que sincroniza algunas propiedades de cada usuario además de asegurarme de que tengan la elegibilidad adecuada. Al final del mes, proceso algunas facturas en función del uso de ese mes.
Utilizo un patrón de estrategia componible para hacer esta sincronización. El programa principal básicamente elige una estrategia maestra en función del día de la semana (sincronizar solo cambios / sincronizar todos) y la hora del semestre en relación con el calendario académico. Si el ciclo de facturación finaliza, también lo compone con una estrategia de facturación. Luego ejecuta la estrategia elegida a través de una interfaz estándar.
No sé qué tan común es esto, pero sentí que encajaba perfectamente con el patrón de estrategia.
fuente
Sé que esta es una pregunta antigua, pero creo que tengo otro ejemplo interesante que implementé recientemente.
Este es un ejemplo muy práctico del patrón de estrategia que se utiliza en un sistema de entrega de documentos.
Tenía un sistema de entrega de PDF que recibía un archivo que contenía muchos documentos y algunos metadatos. Basándose en los metadatos, decidió dónde colocar el documento; por ejemplo, en función de los datos, podría almacenar el documento en
A
,B
oC
sistemas de almacenamiento, o una mezcla de los tres.Diferentes clientes usaban este sistema y tenían diferentes requisitos de gestión de reversión / error en caso de errores: uno quería que el sistema de entrega se detuviera ante el primer error, dejara todos los documentos ya entregados en sus almacenes, pero detuviera el proceso y no entregara nada más. ; otro quería que se revertiera
B
en caso de errores al almacenarC
, pero dejar lo que ya se envióA
. Es fácil imaginar que un tercero o cuarto también tendrá diferentes necesidades.Para resolver el problema, he creado una clase de entrega básica que contiene la lógica de entrega, además de métodos para revertir cosas de todos los almacenamientos. En realidad, el sistema de entrega no llama a esos métodos directamente en caso de errores. En su lugar, la clase usa Inyección de dependencia para recibir una clase de "Estrategia de reversión / manejo de errores" (basada en el cliente que usa el sistema), que se llama en caso de errores, que a su vez llama a los métodos de reversión si es apropiado para esa estrategia.
La clase de entrega en sí informa lo que está sucediendo a la clase de estrategia (qué documentos se entregaron a qué almacenamientos y qué fallas sucedieron), y siempre que ocurre un error, pregunta a la estrategia si continuar o no. Si la estrategia dice "deténgalo", la clase llama al método "cleanUp" de la estrategia, que usa la información reportada previamente para decidir qué métodos de reversión llamar desde la clase de entrega, o simplemente no hacer nada.
Así que ahora tengo dos estrategias diferentes: una es la
QuitterStrategy
(que se cierra con el primer error y no limpia nada) y la otra es laMaximizeDeliveryToAStrategy
(que intenta en la medida de lo posible no abortar el proceso y nunca revertir las cosas entregadas al almacenamientoA
, pero deshace cosas deB
si la entregaC
falla).Según tengo entendido, este es un ejemplo del patrón de estrategia. Si usted (sí, está leyendo) cree que estoy equivocado, por favor comente a continuación y hágamelo saber. Tengo curiosidad por saber qué constituiría un uso "puro" del patrón de estrategia y qué aspectos de mi implementación violan la definición. Creo que se ve un poco divertido porque la interfaz de estrategia es un poco gruesa. Todos los ejemplos que he visto hasta ahora utilizan un solo método, pero sigo pensando que encapsula un algoritmo (si una parte de la lógica empresarial puede considerarse un algoritmo, lo cual creo que sí).
Dado que la estrategia también recibe notificaciones sobre eventos durante la ejecución de la entrega, también se puede considerar un observador , pero esa es otra historia.
Al hacer una pequeña investigación, parece que se trata de un "patrón compuesto" (como MVC, un patrón que utiliza múltiples patrones de diseño debajo de una manera particular) llamado Asesor . Es un asesor sobre si la entrega debe continuar o no, pero también es un manejador de errores activo, ya que puede revertir cosas cuando se le solicite.
De todos modos, este es un ejemplo bastante complejo que puede hacer que sienta que los usos del patrón de estrategia son demasiado simples / tontos. Puede ser realmente complejo e incluso más aplicable cuando se usa junto con otros patrones.
fuente
El patrón de estrategia es el patrón más comúnmente utilizado, especialmente para validaciones y algoritmos de clasificación.
Déjame explicarte con un sencillo ejemplo práctico.
El código de prueba para esto es
El mismo ejemplo se toma de http://coder2design.com/strategy-pattern/
fuente
Un buen ejemplo de patrón de estrategia sería en un juego donde podemos tener diferentes personajes y cada personaje puede tener múltiples armas para atacar pero a la vez puede usar una sola arma. Así que tenemos el personaje como contexto, por ejemplo, Rey, Comandante, Caballero, Soldado y arma como estrategia donde ataque () podría ser el método / algoritmo que depende de las armas que se utilicen. Entonces, si las clases de armas concretas fueran Sword, Axe, Crossbow, BowAndArrow, etc., todas implementarían el método attack (). Estoy seguro de que no se necesitan más explicaciones.
fuente
Usé el enfoque de estrategia en un motor bastante complejo en una aplicación que es un buen ejemplo. Básicamente, la función del motor era buscar primero una lista de personas que tenían un widget, su segunda función era averiguar cuáles eran las 10 mejores personas con un widget en función de un número desconocido de parámetros (cosas como precio, distancia, negocios anteriores juntos , cantidad en stock, opciones de envío, etc., etc., etc.)
Básicamente, lo que hicimos fue dividir el problema en dos estrategias, la primera de las cuales fue la recuperación de datos, ya que sabíamos que teníamos múltiples fuentes de nuestros widgets y necesitábamos poder obtener los datos y transformarlos en una estructura común.
Luego también nos dimos cuenta de que teníamos múltiples algoritmos, algunos se basaban en ponderar los parámetros, otros eran muy extraños y propicios y no podía hacerles justicia sin sacar visios y gráficos y bueno, ya entiendes, teníamos muchos algoritmos para seleccionando a las mejores personas.
Nuestro servicio en sí era muy importante, esencialmente definía las entradas, salidas e hizo cierta normalización de los datos, también usó un patrón de proveedor para conectar los proveedores de datos específicos de la aplicación y los proveedores de algoritmos que usaron la estrategia. Este fue un sistema bastante efectivo.
Tuvimos algunos debates si estábamos usando una estrategia o un patrón de plantilla que nunca resolvimos.
fuente
¿Está seguro de que el estado de una "orden" no es un patrón de estado? Tengo el presentimiento de que un pedido no se manejará de manera diferente según su estado.
Tomemos, por ejemplo, el método Enviar en el pedido:
El mejor ejemplo del patrón de estado (y otros patrones) que encontré fue en el libro " Head First Design Patterns ", que es asombroso. Un segundo cercano será la serie de patrones de blogs de David Cumps .
fuente
Supongamos que desea escribir un algoritmo para calcular el enésimo día X de un mes y año determinados, por ejemplo, el segundo lunes de octubre de 2014. Quiere utilizar la clase Time de Android
android.text.format.Time
para representar la fecha, pero también quiere escribir un algoritmo genérico que también se puede aplicar ajava.util.Calendar
.Esto es lo que hice.
En DatetimeMath.java:
En TimeMath.java:
En OrdinalDayOfWeekCalculator.java, la clase con el algoritmo genérico:
En mi aplicación de Android, llamaría algo como
Si quiero reutilizar el mismo algoritmo para
java.util.Calendar
, simplemente escribiría una clase CalendarMath que implemente los tres métodos en DatetimeMath y luego usaríafuente
fuente
Hace unas semanas, agregué una interfaz Java común que fue implementada por uno de nuestros objetos de dominio. Este objeto de dominio se cargó desde la base de datos y la representación de la base de datos era un esquema en estrella con más de 10 ramas. Una de las consecuencias de tener un objeto de dominio tan pesado es que hemos tenido que hacer otros objetos de dominio que representaban el mismo esquema, aunque menos pesado. Así que hice que los otros objetos ligeros implementaran la misma interfaz. Dicho de otra manera, teníamos:
Originalmente, quería usar
CollectibleElephant
para ordenarElephant
s. Muy rápidamente, mis compañeros de equipo se apresuraronCollectibleElephant
a ejecutar controles de seguridad, filtrarlos a medida que los enviaban a la GUI, etc.fuente
Tuvimos que crear una interfaz de aprovisionamiento de terceros para una plataforma empresarial con una base de datos muy complicada. El envío de datos para ser aprovisionados fue como una lista de nuestros tipos de datos que se colocaron en una cola de prioridad en nuestra aplicación para que pudieran escribirse en la base de datos en el orden correcto debido a las dependencias.
El proceso para escribir esos datos fue bastante simple, seguir apareciendo en la parte superior de la cola de prioridad y luego elegir una estrategia basada en el tipo de objeto que extrae.
fuente
De wikipedia
En la aplicación Windows Paint, puede ver un patrón de estrategia en el que puede elegir la forma y el color de forma independiente en diferentes secciones. Aquí la forma y el color son los algoritmos que pueden cambiar en tiempo de ejecución.
Si desea dibujar un círculo con color rojo, en lugar de proporcionar una opción de 'RedCircle', le permiten elegir el círculo y el color de su elección.
Sin patrón de estrategia aumentará el número de clases con el producto cartesiano de forma y color. Además, la interfaz cambia para cada implementación.
fuente
Imagina un juego de disparos con enemigos de IA, por ejemplo. Desea que luchen continuamente de diferentes maneras según lo que suceda. Con el patrón de estrategia, puede realizar un ciclo continuo y cambiar dinámicamente cómo se realizará una acción específica.
fuente