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 te permite definir una familia de algoritmos, encapsular cada uno en su propia clase y hacer que sean intercambiables. En lugar de codificar directamente un comportamiento específico, puedes intercambiar algoritmos durante la ejecución sin cambiar el código que los utiliza.
Imagina un sistema de pagos que admita múltiples métodos de pago. Sin el patrón Strategy, terminarías 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 de contexto mantiene una referencia a una estrategia y delega el trabajo en ella. 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 dinámicamente el comportamiento del pago:
ShoppingCart cart = new ShoppingCart();
cart.setPaymentStrategy(new CreditCardPayment());
cart.checkout(100); // Pagado 100 vía Credit Card
cart.setPaymentStrategy(new PayPalPayment());
cart.checkout(50); // Pagado 50 vía PayPalEl patrón Strategy destaca cuando tienes varias formas de realizar una acción y quieres cambiar fácilmente entre ellas. Añadir 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¡Construyamos un sistema de formato de texto usando el patrón Strategy! Crearás un sistema en el que se puedan intercambiar distintas estrategias de formato durante la ejecución para transformar el texto de varias maneras, perfecto para una aplicación que necesita admitir múltiples formatos de salida.
Organizarás tu código en cuatro archivos:
TextFormatter.java: Define la interfazTextFormatterque implementarán todas las estrategias de formato. Debe declarar un único métodoString format(String text)que recibe una cadena y devuelve la versión con formato.Formatters.java: Crea tres estrategias concretas que implementen tu interfazTextFormatter:UpperCaseFormatter: transforma el texto para que todas las letras estén en mayúsculas.LowerCaseFormatter: transforma el texto para que todas las letras estén en minúsculas.TitleCaseFormatter: escribe en mayúscula la primera letra de cada palabra y convierte el resto a minúsculas. Las palabras están separadas por espacios.TextEditor.java: Crea la clase de contexto que utiliza una estrategia de formato. TuTextEditordebe tener:Un campo privado para almacenar la estrategia actual de
TextFormatter.Un método
setFormatter(TextFormatter formatter)que cambie la estrategia de formato activa.Un método
publishText(String text)que aplique el formateador actual al texto e imprimaPublished: [formatted text]. Si no se ha establecido ningún formateador, debe imprimirPublished: [original text]sin cambios.Main.java: ¡Integra tu sistema de estrategias! Recibirás dos entradas: el texto que se va a formatear (String) y el estilo de formato (String:"upper","lower"o"title").Crea un
TextEditory llama primero apublishTextcon el texto de entrada antes de establecer cualquier formateador (para demostrar el comportamiento predeterminado).Después, según la entrada de estilo, establece la estrategia de formato adecuada y vuelve a llamar a
publishTextcon el mismo texto para mostrar el resultado con formato.
Recibirás dos entradas en orden: el texto que se va a formatear (String) y el estilo de formato (String).
Por ejemplo, con las entradas hello world y title, el resultado sería:
Published: hello world
Published: Hello WorldObserva que TextEditor no sabe nada sobre la lógica específica de formato. Simplemente delega en la estrategia que esté establecida en ese momento. ¡Esto hace que sea muy fácil añadir nuevos estilos de formato sin tocar el código del editor!
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: Crea una instancia de TextEditor
// TODO: Llama a publishText con el texto de entrada (antes de establecer cualquier formateador)
// TODO: Según la entrada de estilo ("upper", "lower" o "title"),
// establece el formateador apropiado y llama a publishText de nuevo
}
}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 IteratorPractica por tu cuenta: Compilador de Java online