Patrón Strategy
Parte de la sección Programación Orientada a Objetos del Journey de Java de Coddy — lección 69 de 87.
El Patrón Strategy es un patrón de diseño de comportamiento que permite definir una familia de algoritmos, encapsular cada uno en su propia clase y hacerlos intercambiables. En lugar de codificar de forma rígida un comportamiento específico, puedes intercambiar algoritmos en tiempo de ejecución sin cambiar el código que los utiliza.
Imagine un sistema de pago que admita múltiples métodos de pago. Sin el Patrón Strategy, terminaría con una lógica condicional desordenada. Con él, cada método de pago se convierte en su propia estrategia:
interface PaymentStrategy {
void pay(int amount);
}
class CreditCardPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " via Credit Card");
}
}
class PayPalPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " via PayPal");
}
}La clase context mantiene una referencia a una estrategia y le delega el trabajo. La clave es que el contexto no sabe qué estrategia concreta está utilizando; solo conoce la interfaz:
class ShoppingCart {
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy strategy) {
this.paymentStrategy = strategy;
}
public void checkout(int amount) {
paymentStrategy.pay(amount);
}
}Ahora puedes cambiar el comportamiento del pago dinámicamente:
ShoppingCart cart = new ShoppingCart();
cart.setPaymentStrategy(new CreditCardPayment());
cart.checkout(100); // Pagado 100 mediante tarjeta de crédito
cart.setPaymentStrategy(new PayPalPayment());
cart.checkout(50); // Pagado 50 mediante PayPalEl Patrón Strategy brilla cuando tienes múltiples formas de realizar una acción y quieres cambiar entre ellas fácilmente. Agregar un nuevo método de pago simplemente significa crear una nueva clase que implemente PaymentStrategy—no se requieren cambios en el código existente.
Desafío
Fácil¡Vamos a construir un sistema de formateo de texto utilizando el Patrón Strategy! Crearás un sistema donde diferentes estrategias de formateo se pueden intercambiar en tiempo de ejecución para transformar el texto de varias maneras—perfecto para una aplicación que necesita soportar múltiples formatos de salida.
Organizarás tu código en cuatro archivos:
TextFormatter.java: Define la interfazTextFormatterque implementarán todas las estrategias de formateo. Debe declarar un único métodoString format(String text)que recibe una cadena y devuelve la versión formateada.Formatters.java: Crea tres estrategias concretas que implementen tu interfazTextFormatter:UpperCaseFormatter- transforma el texto a letras mayúsculas.LowerCaseFormatter- transforma el texto a letras minúsculas.TitleCaseFormatter- pone en mayúscula la primera letra de cada palabra mientras que el resto queda en minúscula. Las palabras están separadas por espacios.TextEditor.java: Crea la clase de contexto que utiliza una estrategia de formateo. TuTextEditordebe tener:Un campo privado para mantener la estrategia
TextFormatteractual.Un método
setFormatter(TextFormatter formatter)que cambia la estrategia de formateo activa.Un método
publishText(String text)que aplica el formateador actual al texto e imprimePublished: [formatted text]. Si no se ha establecido ningún formateador, debe imprimirPublished: [original text]sin cambios.Main.java: ¡Une tu sistema de estrategias! Recibirás dos entradas: el texto a formatear (String) y el estilo de formateo (String:"upper","lower", o"title").Crea un
TextEditory primero llama apublishTextcon tu texto de entrada antes de establecer cualquier formateador (demostrando el comportamiento por defecto).Luego, basándote en la entrada del estilo, establece la estrategia de formateador apropiada y llama a
publishTextde nuevo con el mismo texto para mostrar el resultado formateado.
Recibirás dos entradas en orden: el texto a formatear (String) y el estilo de formateo (String).
Por ejemplo, con las entradas hello world y title, tu salida sería:
Published: hello world
Published: Hello World¡Observa cómo el TextEditor no sabe nada sobre la lógica de formateo específica—simplemente delega en cualquier estrategia que esté establecida actualmente! ¡Esto hace que sea trivial añadir nuevos estilos de formateo sin tocar el código del editor!
Hoja de referencia
El Patrón Strategy es un patrón de diseño de comportamiento que define una familia de algoritmos, encapsula cada uno en su propia clase y los hace intercambiables. Permite intercambiar algoritmos en tiempo de ejecución sin cambiar el código que los utiliza.
Componentes Clave
Interfaz Strategy: Define la interfaz común para todas las estrategias concretas.
interface PaymentStrategy {
void pay(int amount);
}Estrategias Concretas: Implementan la interfaz de estrategia con algoritmos específicos.
class CreditCardPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " via Credit Card");
}
}
class PayPalPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " via PayPal");
}
}Clase Contexto: Mantiene una referencia a una estrategia y le delega el trabajo. El contexto solo conoce la interfaz, no la implementación concreta.
class ShoppingCart {
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy strategy) {
this.paymentStrategy = strategy;
}
public void checkout(int amount) {
paymentStrategy.pay(amount);
}
}Uso
Las estrategias se pueden cambiar dinámicamente en tiempo de ejecución:
ShoppingCart cart = new ShoppingCart();
cart.setPaymentStrategy(new CreditCardPayment());
cart.checkout(100); // Pagado 100 a través de Tarjeta de Crédito
cart.setPaymentStrategy(new PayPalPayment());
cart.checkout(50); // Pagado 50 a través de PayPalBeneficios
El Patrón Strategy es ideal cuando se tienen múltiples formas de realizar una acción y se desea cambiar entre ellas fácilmente. Añadir una nueva estrategia simplemente significa crear una nueva clase que implemente la interfaz de estrategia; no se requieren cambios en el código existente.
Pruébalo tú mismo
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String text = scanner.nextLine();
String style = scanner.nextLine();
// TODO: Crear una instancia de TextEditor
// TODO: Llamar a publishText con el texto de entrada (antes de configurar cualquier formateador)
// TODO: Basado en la entrada de estilo ("upper", "lower" o "title"),
// configurar el formateador apropiado y llamar a publishText nuevamente
}
}Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de OOP
Archivos externosIntroducción a la OOPClases vs. ObjetosLa palabra clave thisMétodosCampos (Atributos)Método constructorSobrecarga de constructoresResumen - Calculadora simple4Herencia
Herencia básica (extends)La palabra clave superSobrescritura de métodos (@Override)Encadenamiento de constructoresLa clase ObjectHerencia simple y multinivelPor qué no hay herencia múltiple de clasesResumen - Jerarquía de empleados7Métodos especiales y la clase Object
Método toString()equals() y hashCode()Método clone()compareTo() y ComparableInterfaz ComparatorResumen - Ordenamiento personalizado2Modificadores de acceso y encapsulamiento
Visión general de los niveles de accesoMétodos Getter y SetterOcultamiento de informaciónLa palabra clave finalResumen - Gestor de cuentas bancarias5Polimorfismo
Fundamentos de sobrecarga de métodosSobrescritura de métodos (tiempo de ejecución)Upcasting y DowncastingEl operador instanceofClases y métodos abstractosResumen - Calculadora de figuras8Conceptos avanzados de POO
Composición vs. HerenciaAgregación vs. ComposiciónClases internas, anidadas y anónimasEnums y métodos de EnumRecords (Java 16+)Clases selladas (Java 17+)11Patrones de diseño - Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón BuilderPatrón ObserverPatrón Strategy3Propiedades de clase y miembros estáticos
Variables de instancia vs. estáticasMétodos estáticosBloques estáticosConstantes (static final)Repaso - Contador y utilidad6Interfaces y Clases Abstractas
Introducción a las InterfacesImplementación de InterfacesImplementación de Múltiples InterfacesMétodos Default y Static en InterfacesClases Abstractas vs InterfacesInterfaces FuncionalesResumen - Sistema de Pagos9Genéricos
Introducción a los genéricosClases genéricasMétodos genéricosParámetros de tipo delimitadosComodines (?, extends, super)Resumen - Contenedor genérico12Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Iterator