Menu
Coddy logo textTech

Patrón Strategy

Parte de la sección Programación Orientada a Objetos del Journey de GO de Coddy. Lección 90 de 107.

El patrón Strategy te permite definir una familia de algoritmos, encapsular cada uno y hacer que sean intercambiables en tiempo de ejecución. A diferencia de Observer, donde varios objetos reaccionan a un evento, Strategy permite que un solo objeto cambie dinámicamente entre diferentes comportamientos.

En Go, implementamos Strategy definiendo una interfaz para el algoritmo e inyectando diferentes implementaciones en una estructura de contexto:

type PaymentStrategy interface {
    Pay(amount float64) string
}

type CreditCard struct{}
func (c CreditCard) Pay(amount float64) string {
    return fmt.Sprintf("Paid %.2f via Credit Card", amount)
}

type PayPal struct{}
func (p PayPal) Pay(amount float64) string {
    return fmt.Sprintf("Paid %.2f via PayPal", amount)
}

La estructura de contexto contiene una referencia a la interfaz de estrategia, lo que permite cambiar el algoritmo sin modificar el código del contexto:

type Checkout struct {
    strategy PaymentStrategy
}

func (c *Checkout) SetStrategy(s PaymentStrategy) {
    c.strategy = s
}

func (c *Checkout) ProcessPayment(amount float64) string {
    return c.strategy.Pay(amount)
}

Ahora puedes cambiar el método de pago durante la ejecución:

checkout := &Checkout{}

checkout.SetStrategy(CreditCard{})
fmt.Println(checkout.ProcessPayment(100.00))  // Pagado 100.00 vía Credit Card

checkout.SetStrategy(PayPal{})
fmt.Println(checkout.ProcessPayment(50.00))   // Pagado 50.00 vía PayPal

Strategy es ideal cuando tienes varias formas de realizar una operación y necesitas seleccionar una en función de la entrada del usuario, la configuración o las condiciones de ejecución. Los casos de uso comunes incluyen algoritmos de ordenación, métodos de compresión y reglas de validación.

challenge icon

Desafío

Fácil

¡Construyamos un sistema de formato de texto usando el patrón Strategy! Crearás diferentes estrategias de formato que se pueden intercambiar en tiempo de ejecución, lo que permitirá que el mismo procesador de texto produzca distintos estilos de salida sin cambiar su código principal.

Organizarás tu código en tres archivos:

  • formatter.go: Define tu interfaz de estrategia y las estrategias concretas de formato.

    Crea una interfaz TextFormatter con un método Format(text string) string que transforme el texto según las reglas de la estrategia.

    Implementa tres estrategias de formato:

    • UppercaseFormatter: convierte el texto completamente a mayúsculas
    • SnakeCaseFormatter: convierte los espacios en guiones bajos y convierte el texto a minúsculas
    • TitleFormatter: escribe en mayúscula la primera letra de cada palabra (las palabras están separadas por espacios)
  • processor.go: Crea tu estructura de contexto que utiliza la estrategia de formato.

    Construye una estructura TextProcessor que contenga una estrategia TextFormatter. Añade estos métodos:

    • SetFormatter(f TextFormatter) para cambiar la estrategia de formato activa
    • Process(text string) string que aplica el formateador actual al texto

    Crea también un constructor NewTextProcessor() que devuelva un procesador sin ningún formateador inicial establecido.

  • main.go: Demuestra cómo cambiar de estrategia en tiempo de ejecución.

    Lee un texto y después lee una cantidad de operaciones de formato. Para cada operación, lee el tipo de formato (upper, snake o title), establece el formateador correspondiente en tu procesador, procesa el texto original e imprime el resultado.

Se proporcionarán las siguientes entradas:

  • Línea 1: El texto que se va a formatear
  • Línea 2: Número de operaciones de formato
  • Líneas siguientes: Tipo de formato para cada operación

Por ejemplo, dada la siguiente entrada:

hello world today
3
upper
snake
title

Tu salida debería ser:

HELLO WORLD TODAY
hello_world_today
Hello World Today

Y dada la siguiente entrada:

Go Programming Language
2
snake
upper

Tu salida debería ser:

go_programming_language
GO PROGRAMMING LANGUAGE

Y dada la siguiente entrada:

design patterns are useful
1
title

Tu salida debería ser:

Design Patterns Are Useful

Observa cómo el mismo TextProcessor produce salidas completamente diferentes simplemente cambiando su estrategia de formato. Al procesador no le importa ni sabe qué formateador específico está utilizando. ¡Simplemente delega en la estrategia que esté establecida actualmente!

Pruébalo tú mismo

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	
	// Lee el texto a formatear
	text, _ := reader.ReadString('\n')
	text = strings.TrimSpace(text)
	
	// Lee el número de operaciones
	countStr, _ := reader.ReadString('\n')
	count, _ := strconv.Atoi(strings.TrimSpace(countStr))
	
	// Crea un nuevo procesador de texto
	processor := NewTextProcessor()
	
	// Procesa cada operación de formato
	for i := 0; i < count; i++ {
		formatType, _ := reader.ReadString('\n')
		formatType = strings.TrimSpace(formatType)
		
		// TODO: Basado en formatType ("upper", "snake", o "title"),
		// establece el formateador apropiado en el processor
		// e imprime el texto procesado
		
	}
}
quiz iconPonte a prueba

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

Practica por tu cuenta: Compilador de Go online