Ejemplo del mundo real del patrón de estrategia

He estado leyendo sobre el director de OCP y cómo usar el patrón de estrategia para lograr esto.

Iba a tratar de explicar esto a un par de personas, pero el único ejemplo en el que puedo pensar es usar diferentes clases de validación basadas en qué estado es 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 algún ejemplo del mundo real donde pienses que un patrón de estrategia es común?

¿Qué tal esto?

Tienes que encriptar un archivo.

Para archivos pequeños, puede usar la estrategia “en memoria”, donde el archivo completo se lee y se guarda en la memoria (digamos para archivos <1 gb)

Para archivos grandes, puede usar otra estrategia, donde partes del archivo se leen en la memoria y los resultados parciales encriptados se almacenan en archivos tmp.

Estas pueden ser dos estrategias diferentes para la misma tarea.

El código del cliente se vería igual:

File file = getFile(); Cipher c = CipherFactory.getCipher( file.size() ); c.performAction(); // implementations: interface Cipher { public void performAction(); } class InMemoryCipherStrategy implements Cipher { public void performAction() { // load in byte[] .... } } class SwaptToDiskCipher implements Cipher { public void performAction() { // swapt partial results to file. } } 

los

  Cipher c = CipherFactory.getCipher( file.size() ); 

Devolvería la instancia de estrategia correcta para el cifrado.

Espero que esto ayude.

(Ni siquiera sé si Cipher es la palabra correcta: P)

De nuevo, una publicación anterior pero aún 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 muchas veces cuando los directores del proyecto dicen: “Queremos que la aplicación haga ‘X’, pero ‘X’ todavía no está claro y puede cambiar en el 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: debemos verificar los elementos de acuerdo con “Algunas reglas”, 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 mueve, pero quizás en el futuro, también debería poder nadar, volar, teletransportarse, esconderse bajo tierra, etc.

  • Almacenamiento de información: queremos que la aplicación almacene información en la base de datos, pero luego puede necesitar guardar un archivo o hacer un webcall

  • Salida: Necesitamos dar salida a 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 está “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 comerciales todavía no están del todo claras, y podrían surgir nuevas reglas en cualquier momento. El poder del patrón estratético es que hice un RuleAgent, al que se le da una lista de IRules.

 public interface IRule { bool IsApproved(Assignment assignment); } 

En el momento de asignar un producto a una persona, creo un RuleAgent, le doy una lista de reglas (que todas implementan IRule) y le pido que valide una tarea. Se ejecutará a través de todas sus reglas. Que, debido a que todos implementan la misma interfaz, todos tienen el método IsApproved y devuelven falso si alguno de ellos devuelve false.

Ahora, cuando, por ejemplo, el gerente aparece repentinamente y dice: también tenemos que rechazar todas las asignaciones a pasantes, o todas las asignaciones a personas que trabajan horas extras … Usted hace nuevas clases como esta:

 public OvertimeRule : IRule { public bool IsApproved(Assignment assignment) //Interface method { if (assignment.Person.Timesheet >= 40) { return false; } return true; } } public InternRule : IRule { public bool IsApproved(Assignment assignment) //Interface method { if (assignment.Person.Title == "Intern") { return false; } return true; } } 

Verá que no tiene que seguir agregando o eliminando sentencias if o código, simplemente cree una nueva clase de regla que implemente la interfaz IRUle y cámbiela 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 de la unidad de la aplicación

Él 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 vistas, la mayoría de los suscriptores, fecha de creación, más actividad, menor cantidad de comentarios, etc.), y en caso de que la administración todavía no sepa exactamente cómo ordenar, y quiera 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 el pedido en una implementación concreta de la interfaz IOrderAlgorithm. Puede hacer un “Orden del comentario”, “Organizador de actividad”, etc. Y simplemente cambie estos cuando surjan nuevos requisitos.

Puedo pensar en varios ejemplos bastante simples:

  • Ordenando una lista La estrategia es la comparación utilizada para decidir cuál de los dos elementos de la lista es “Primero”
  • Es posible que tenga una aplicación donde el algoritmo de clasificación en sí (QuickSort, HeapSort, etc.) se puede elegir en tiempo de ejecución
  • Anexos, diseños y filtros en Log4Net y Log4j
  • Gestores de diseño en kits de herramientas de interfaz de usuario
  • Compresión de datos. Es posible que tenga una interfaz ICompressor cuyo único método se parece a esto:

    byte [] compress (entrada byte []);

    Sus clases de compresión concretas pueden ser cosas como RunLengthCompression, DeflateCompression, etc.

Un uso común del patrón de estrategia es definir estrategias de clasificación personalizadas (en idiomas sin funciones de orden superior), por ejemplo, ordenar una lista de cadenas por longitud en Java, pasando una clase interna anónima (una implementación de la interfaz de estrategia):

 List names = Arrays.asList("Anne", "Joe", "Harry"); Collections.sort(names, new Comparator() { public int compare(String o1, String o2) { return o1.length() - o2.length(); } }); Assert.assertEquals(Arrays.asList("Joe", "Anne", "Harry"), names); 

De manera similar, las estrategias se pueden usar para consultas nativas con bases de datos de objetos, por ejemplo, en db4o:

 List set = db.query(new Predicate() { public boolean match(Document candidate) { return candidate.getSource().contains(source); } }); 

Tengo una aplicación que sincroniza su base de usuarios cada día con nuestro directorio empresarial. Los usuarios son elegibles o no elegibles en función de su estado en la Universidad. Cada día el progtwig de aprovisionamiento se realiza y se asegura de que los que se supone que sean elegibles estén aprovisionados en la aplicación y aquellos que no están aprovisionados (en realidad según un algoritmo de degradación elegante, pero eso no viene al caso). El sábado hago una actualización más exhaustiva que sincroniza algunas propiedades de cada usuario y se asegura de que tengan la elegibilidad adecuada. Al final del mes, realicé el procesamiento de las facturas según el uso de ese mes.

Uso un patrón de estrategia composable para hacer esta sincronización. El progtwig principal básicamente elige una estrategia maestra según el día de la semana (solo cambios de sincronización / sincronización) y la hora del semestre en relación con el calendario académico. Si el ciclo de facturación está finalizando, también lo compone con una estrategia de facturación. A continuación, ejecuta la estrategia elegida a través de una interfaz estándar.

No sé qué tan común es esto, pero sentí que era el ajuste perfecto para el patrón de estrategia.

Notas clave:

  1. La estrategia es un patrón de diseño de comportamiento. Se usa para cambiar entre familia de algoritmos.

  2. Este patrón contiene una interfaz de estrategia abstracta y muchas implementaciones de estrategia concretas ( algoritmos ) de esa interfaz.

  3. La aplicación usa solo la interfaz de estrategia. Dependiendo de algún parámetro de configuración, la estrategia concreta se etiquetará a la interfaz .

Diagtwig UML de wikipedia

enter image description here

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.

Echa un vistazo a un ejemplo simple. Este ejemplo se puede extender a las aplicaciones de venta minorista en línea, que ofrece descuentos en artículos de carrito de la compra en días especiales / horas felices fácilmente.

 import java.util.*; /* Interface for Strategy */ interface OfferStrategy { public String getName(); public double getDiscountPercentage(); } /* Concrete implementation of base Strategy */ class NoDiscountStrategy implements OfferStrategy{ public String getName(){ return this.getClass().getName(); } public double getDiscountPercentage(){ return 0; } } /* Concrete implementation of base Strategy */ class QuarterDiscountStrategy implements OfferStrategy{ public String getName(){ return this.getClass().getName(); } public double getDiscountPercentage(){ return 0.25; } } /* Context is optional. But if it is present, it acts as single point of contact for client. Multiple uses of Context 1. It can populate data to execute an operation of strategy 2. It can take independent decision on Strategy creation. 3. In absence of Context, client should be aware of concrete strategies. Context acts a wrapper and hides internals 4. Code re-factoring will become easy */ class StrategyContext { double price; // price for some item or air ticket etc. Map strategyContext = new HashMap(); StrategyContext(double price){ this.price= price; strategyContext.put(NoDiscountStrategy.class.getName(),new NoDiscountStrategy()); strategyContext.put(QuarterDiscountStrategy.class.getName(),new QuarterDiscountStrategy()); } public void applyStrategy(OfferStrategy strategy){ /* Currently applyStrategy has simple implementation. You can use Context for populating some more information, which is required to call a particular operation */ System.out.println("Price before offer :"+price); double finalPrice = price - (price*strategy.getDiscountPercentage()); System.out.println("Price after offer:"+finalPrice); } public OfferStrategy getStrategy(int monthNo){ /* In absence of this Context method, client has to import relevant concrete Strategies everywhere. Context acts as single point of contact for the Client to get relevant Strategy */ if ( monthNo < 6 ) { return strategyContext.get(NoDiscountStrategy.class.getName()); }else{ return strategyContext.get(QuarterDiscountStrategy.class.getName()); } } } public class StrategyDemo{ public static void main(String args[]){ StrategyContext context = new StrategyContext(100); System.out.println("Enter month number between 1 and 12"); int month = Integer.parseInt(args[0]); System.out.println("Month ="+month); OfferStrategy strategy = context.getStrategy(month); context.applyStrategy(strategy); } } 

salida:

 Enter month number between 1 and 12 Month =1 Price before offer :100.0 Price after offer:100.0 Enter month number between 1 and 12 Month =7 Price before offer :100.0 Price after offer:75.0 

Artículos útiles:

patrón de estrategia por dzone

patrón de estrategia por fuente

Sé que esta es una vieja pregunta, pero creo que tengo otro ejemplo interesante que implementé recientemente.

Este es un ejemplo muy práctico del patrón de estrategia que se usa 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. En función de los metadatos, decidió dónde colocar el documento; Por ejemplo, según los datos, podría almacenar el documento en sistemas de almacenamiento A , B o C , o una combinación de los tres.

Diferentes clientes usaron este sistema y tenían diferentes requisitos de reversión / manejo de errores en caso de errores: uno quería que el sistema de entrega se detuviera en el primer error, dejar todos los documentos ya entregados en sus almacenes, pero detener el proceso y no entregar nada más ; otro quería que se deshaga de B en caso de errores al almacenar en C , pero deja lo que ya se entregó a 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 almacenes. Esos métodos realmente no son llamados por el sistema de entrega directamente en caso de errores. En cambio, la clase usa Dependency Injection para recibir una clase “Rollback / Error Handling Strategy” (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 informa qué está pasando con la clase de estrategia (qué documentos se entregaron a qué almacenamientos y qué fallas se produjeron), y cada vez que se produce un error, pregunta a la estrategia si continuará o no. Si la estrategia dice “detenerlo”, la clase llama al método de “limpieza” de la estrategia, que utiliza la información previamente informada para decidir qué métodos de reversión llamar desde la clase de entrega, o simplemente no hace nada.

 rollbackStrategy.reportSuccessA(...); rollbackStrategy.reportFailureB(...); if (rollbackStrategy.mustAbort()) { rollbackStrategy.rollback(); // rollback whatever is needed based on reports return false; } 

Así que ahora tengo dos estrategias diferentes: una es QuitterStrategy (que se cierra en el primer error y no limpia nada) y la otra es MaximizeDeliveryToAStrategy (que intenta tanto como sea posible no abortar el proceso y nunca restituir las cosas entregadas al almacenamiento A , pero revierte cosas de B si la entrega a C falla).

Desde mi punto de vista, este es un ejemplo del patrón de estrategia. Si usted (sí, usted lee) piensa que estoy equivocado, por favor coméntelo abajo y hágamelo saber. Tengo curiosidad sobre 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 raro porque la interfaz de la estrategia es un poco gorda. Todos los ejemplos que he visto hasta ahora usan solo un método, pero sigo creyendo que esto encapsula un algoritmo (si una parte de la lógica de negocios puede considerarse un algoritmo, que creo que sí).

Como a la estrategia también se le notifica sobre los eventos durante la ejecución de la entrega, también se la puede considerar un observador , pero esa es otra historia.

A partir de 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 controlador activo de errores, ya que puede deshacer cosas cuando se le pida.

De todos modos, este es un ejemplo bastante complejo que podría hacer que la sensación tuya de 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.

El patrón de estrategia es el patrón más utilizado especialmente para validaciones y algoritmos de clasificación.

Déjame explicarte con un simple ejemplo práctico

 enum Speed { SLOW, MEDIUM, FAST; } class Sorter { public void sort(int[] input, Speed speed) { SortStrategy strategy = null; switch (speed) { case SLOW: strategy = new SlowBubbleSortStrategy(); break; case MEDIUM: strategy = new MediumInsertationSortStrategy(); break; case FAST: strategy = new FastQuickSortStrategy(); break; default: strategy = new MediumInsertationSortStrategy(); } strategy.sort(input); } } interface SortStrategy { public void sort(int[] input); } class SlowBubbleSortStrategy implements SortStrategy { public void sort(int[] input) { for (int i = 0; i < input.length; i++) { for (int j = i + 1; j < input.length; j++) { if (input[i] > input[j]) { int tmp = input[i]; input[i] = input[j]; input[j] = tmp; } } } System.out.println("Slow sorting is done and the result is :"); for (int i : input) { System.out.print(i + ","); } } } class MediumInsertationSortStrategy implements SortStrategy { public void sort(int[] input) { for (int i = 0; i < input.length - 1; i++) { int k = i + 1; int nxtVal = input[k]; while (input[k - 1] > nxtVal) { input[k] = input[k - 1]; k--; if (k == 0) break; } input[k] = nxtVal; } System.out.println("Medium sorting is done and the result is :"); for (int i : input) { System.out.print(i + ","); } } } class FastQuickSortStrategy implements SortStrategy { public void sort(int[] input) { sort(input, 0, input.length-1); System.out.println("Fast sorting is done and the result is :"); for (int i : input) { System.out.print(i + ","); } } private void sort(int[] input, int startIndx, int endIndx) { int endIndexOrig = endIndx; int startIndexOrig = startIndx; if( startIndx >= endIndx) return; int pavitVal = input[endIndx]; while (startIndx <= endIndx) { while (input[startIndx] < pavitVal) startIndx++; while (input[endIndx] > pavitVal) endIndx--; if( startIndx <= endIndx){ int tmp = input[startIndx]; input[startIndx] = input[endIndx]; input[endIndx] = tmp; startIndx++; endIndx--; } } sort(input, startIndexOrig, endIndx); sort(input, startIndx, endIndexOrig); } } 

El código de prueba para esto es

 public class StrategyPattern { public static void main(String[] args) { Sorter sorter = new Sorter(); int[] input = new int[] {7,1,23,22,22,11,0,21,1,2,334,45,6,11,2}; System.out.print("Input is : "); for (int i : input) { System.out.print(i + ","); } System.out.println(); sorter.sort(input, Speed.SLOW); } } 

El mismo ejemplo se toma de http://coder2design.com/strategy-pattern/

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 solo un arma. Así que tenemos el personaje como contexto, por ejemplo Rey, Comandante, Caballero, Soldado y arma como una estrategia donde el ataque () podría ser el método / algoritmo que depende de las armas que se usen. Entonces, si las clases de armas concretas fueran Espada, Hacha, Ballesta, Proa, etc., todos implementarían el método de ataque (). Estoy seguro de que no se necesita una explicación más detallada.

¿Estás seguro de que el estado de una “orden” no es un patrón de Estado? Tengo la corazonada de que un pedido no será manejado de manera diferente dependiendo de su estado.

Tomemos por ejemplo el método Ship on the Order:

 order.Ship(); 
  • Si el método de envío varía en función de su estado, entonces tiene un patrón de estrategia.
  • Sin embargo, si el método Ship () solo tiene éxito cuando se ha pagado el pedido y el pedido aún no se ha enviado, tiene un patrón de estado.

El mejor ejemplo del patrón de estado (y otros patrones) que encontré estaba en el libro ” Head First Design Patterns “, que es increíble. Un próximo segundo será la serie de patrones de blogs de David Cumps .

Supongamos que desea escribir un algoritmo para calcular el enésimo X día de un mes y año determinado, por ejemplo, el segundo lunes de octubre de 2014. Desea utilizar la clase de tiempo Android android.text.format.Time para representar la fecha, pero usted también quiero escribir un algoritmo genérico que también se pueda aplicar a java.util.Calendar .

Esto es lo que hice.

En DatetimeMath.java:

 public interface DatetimeMath { public Object createDatetime(int year, int month, int day); public int getDayOfWeek(Object datetime); public void increment(Object datetime); } 

En TimeMath.java:

 public class TimeMath implements DatetimeMath { @Override public Object createDatetime(int year, int month, int day) { Time t = new Time(); t.set(day, month, year); t.normalize(false); return t; } @Override public int getDayOfWeek(Object o) { Time t = (Time)o; return t.weekDay; } @Override public void increment(Object o) { Time t = (Time)o; t.set(t.monthDay + 1, t.month, t.year); t.normalize(false); } } 

En OrdinalDayOfWeekCalculator.java, la clase con el algoritmo genérico:

 public class OrdinalDayOfWeekCalculator { private DatetimeMath datetimeMath; public OrdinalDayOfWeekCalculator(DatetimeMath m) { datetimeMath = m; } public Object getDate(int year, int month, int dayOfWeek, int ordinal) { Object datetime = datetimeMath.createDatetime(year, month, 1); if (datetimeMath.getDayOfWeek(datetime) == dayOfWeek) { return datetime; } int xDayCount = 0; while (xDayCount != ordinal) { datetimeMath.increment(datetime); if (datetimeMath.getDayOfWeek(datetime) == dayOfWeek) { xDayCount++; } } return datetime; } } 

En mi aplicación de Android, yo llamaría algo así como

 OrdinalDayOfWeekCalculator odowc = new OrdinalDayOfWeekCalculator(new TimeMath()); Time canadianThanksgiving = (Time)odowc.getDate( year, Calendar.OCTOBER, Time.MONDAY, 2); 

Si quiero reutilizar el mismo algoritmo para java.util.Calendar , solo escribiría una clase CalendarMath que implemente los tres métodos en DatetimeMath y luego use

 OrdinalDayOfWeekCalculator odowc2 = new OrdinalDayOfWeekCalculator(new CalendarMath()); Calendar canadianThanksgivingCal = (Calendar)odowc2.getDate( year, Calendar.OCTOBER, Calendar.MONDAY, 2); 

Usé el enfoque de estrategia en un motor bastante complejo en una aplicación que es un buen ejemplo. Básicamente, el rol del motor era ir y primero encontrar una lista de personas que tenían un widget, su segundo rol era descubrir cuáles eran las 10 mejores personas con un widget basado en un número desconocido de parámetros (cosas como la distancia de precios de un negocio anterior juntos , en stock, opciones de envío, etc. etc …)

Esencialmente, lo que hicimos fue dividir el problema en dos estrategias: la primera era la recuperación de datos, ya que sabíamos que teníamos varias fonts de nuestros widgets y necesitábamos poder obtener los datos y transformarlos en una estructura común.

También nos dimos cuenta de que teníamos varios algoritmos, algunos se basaban en ponderar los parámetros, otros eran muy extraños y no podíamos hacerles justicia sin sacar visios y gráficos y, bueno, ya entendía, teníamos muchos algoritmos para seleccionando las mejores personas

Nuestro servicio en sí mismo fue algo que definió esencialmente 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 aplicaciones y los proveedores de algoritmos que usaron la estrategia. Este fue un sistema bastante efectivo.

Tuvimos algunos debates si utilizábamos una estrategia o un patrón de plantilla que nunca resolvimos.

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 fue un esquema en estrella con más de 10 twigs. Una de las consecuencias de tener un objeto de dominio tan pesado es que tuvimos que crear otros objetos de dominio que representaban el mismo esquema, aunque menos pesado. Así que hice que los otros objetos livianos implementaran la misma interfaz. En caso contrario, tenemos:

 public interface CollectibleElephant { long getId(); String getName(); long getTagId(); } public class Elephant implements CollectibleElephant { ... } public class BabyElephant implements CollectibleElephant { ... } 

Originalmente, quería usar CollectibleElephant para ordenar Elephant s. Muy rápido, mis compañeros de equipo se asomaron a CollectibleElephant para ejecutar comprobaciones de seguridad, filtrarlas a medida que se envían a la GUI, etc.

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 a aprovisionar era como una lista de nuestros tipos de datos que se pusieron 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, sigue apareciendo en la parte superior de la cola de prioridad y luego elige una estrategia basada en el tipo de objeto que extraes.

 public class StrategyDemo { public static void main(String[] args) { ShoppingCart cart = new ShoppingCart(); Item item1 = new Item("1234", 10); Item item2 = new Item("5678", 40); cart.addItem(item1); cart.addItem(item2); // pay by paypal cart.pay(new PaypalStrategy("myemail@example.com", "mypwd")); // pay by credit card cart.pay(new CreditCardStrategy("Pankaj Kumar", "1234567890123456", "786", "12/15")); } } interface PaymentStrategy { public void pay(int amount); } class CreditCardStrategy implements PaymentStrategy { private String name; private String cardNumber; private String cvv; private String dateOfExpiry; public CreditCardStrategy(String nm, String ccNum, String cvv, String expiryDate) { this.name = nm; this.cardNumber = ccNum; this.cvv = cvv; this.dateOfExpiry = expiryDate; } @Override public void pay(int amount) { System.out.println(amount + " paid with credit/debit card"); } } class PaypalStrategy implements PaymentStrategy { private String emailId; private String password; public PaypalStrategy(String email, String pwd) { this.emailId = email; this.password = pwd; } @Override public void pay(int amount) { System.out.println(amount + " paid using Paypal."); } } class Item { private String upcCode; private int price; public Item(String upc, int cost) { this.upcCode = upc; this.price = cost; } public String getUpcCode() { return upcCode; } public int getPrice() { return price; } } class ShoppingCart { // List of items List items; public ShoppingCart() { this.items = new ArrayList(); } public void addItem(Item item) { this.items.add(item); } public void removeItem(Item item) { this.items.remove(item); } public int calculateTotal() { int sum = 0; for (Item item : items) { sum += item.getPrice(); } return sum; } public void pay(PaymentStrategy paymentMethod) { int amount = calculateTotal(); paymentMethod.pay(amount); } } 

Desde wikipedia

En la progtwigción de computadoras, el patrón de estrategia (también conocido como patrón de política) es un patrón de diseño de software conductual que permite seleccionar un algoritmo en tiempo de ejecución. En lugar de implementar un solo algoritmo directamente, el código recibe instrucciones de tiempo de ejecución sobre qué familia de algoritmos usar

En la aplicación Windows Paint, puede ver un patrón de estrategia donde 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 el color rojo, en lugar de proporcionar una opción de ‘RedCircle’, le permiten elegir el círculo y el color que desee.

 Shape redCircle = new RedCircle(); // Without stretegy Pattern Shaped redCircle = new Shape("red","circle"); // With Strategy pattern 

Sin un patrón de estrategia, boostá el número de clases con el producto cartesiano de forma y color. También la interfaz cambia para cada implementación.