Strategy — qué es, el patrón estrategia en iOS y Android

Autor: IT Sectr Publicado: 2026-02-18 Tiempo de lectura: 9 min

Strategy (Estrategia) es un patrón de diseño de comportamiento que define una familia de algoritmos intercambiables y coloca cada uno de ellos en una clase separada (Strategy). El patrón permite seleccionar un algoritmo sobre la marcha: el código cliente funciona a través de una interfaz Strategy común, y la implementación concreta se sustituye en tiempo de ejecución. En iOS, el patrón se implementa mediante Protocol + clases de estrategia, en Android — mediante Interface + implementaciones. Strategy es uno de los 23 patrones GoF, ampliamente utilizado para procesamiento de pagos, validación, ordenamiento y filtrado de datos. Para más detalles — consulte la descripción original de GoF.

Puntos clave

  • Strategy — un patrón de comportamiento GoF para una familia de algoritmos intercambiables
  • Encapsulación de algoritmos — cada algoritmo está aislado en su propia clase
  • Interfaz Strategy — un contrato común implementado por todas las estrategias concretas
  • Composición sobre herencia — el contexto mantiene una referencia a una estrategia, no hereda el comportamiento
  • Principio Open/Closed — se pueden añadir nuevas estrategias sin modificar el código existente

¿Qué es el patrón Strategy: esencia y estructura?

Strategy es uno de los 23 patrones GoF (Gang of Four), descrito en el libro "Design Patterns: Elements of Reusable Object-Oriented Software" (1994). El patrón resuelve el problema de seleccionar un algoritmo en tiempo de ejecución. En lugar de escribir una sola clase con múltiples sentencias condicionales (if-else, switch), Strategy propone extraer cada algoritmo en una clase separada con una interfaz común. El contexto (la clase que utiliza la estrategia) mantiene una referencia a la interfaz Strategy y delega la ejecución a la estrategia concreta.

La estructura del patrón incluye tres elementos: Context mantiene una referencia a Strategy y llama a su método; Strategy (interfaz) declara un método común para todos los algoritmos; ConcreteStrategy implementa la interfaz y contiene el algoritmo concreto. El cliente crea la estrategia deseada y la pasa al contexto a través de un constructor, setter o parámetro de método. El contexto no sabe qué estrategia específica se está ejecutando — solo trabaja con la interfaz.

ComponenteRolEjemplo
ContextMantiene una referencia a StrategyPaymentProcessor, Sorter
StrategyInterfaz común para algoritmosProtocol PaymentStrategy
ConcreteStrategyImplementación concreta del algoritmoCardPayment, PayPalPayment

Principio Open/Closed — la principal ventaja de Strategy. El sistema está abierto para extensión (se puede añadir una nueva estrategia) y cerrado para modificación (el código del contexto no necesita cambiar). Sin el patrón, añadir un nuevo algoritmo requiere modificar la clase existente, lo que viola OCP y aumenta el riesgo de errores de regresión. Strategy también reduce el tamaño de las clases: en lugar de una clase de 200 líneas con un switch-case, se obtienen 6 clases de 20 líneas cada una.

Strategy en iOS: implementación en Swift con Protocol

Strategy en Swift se implementa mediante Protocol (interfaz de estrategia) y clases o estructuras de estrategia. Los protocolos de Swift admiten tipos asociados y restricciones genéricas, lo que proporciona flexibilidad al diseñar estrategias. El contexto suele ser una clase ViewModel o servicio que acepta la estrategia en init o mediante una propiedad. El patrón se utiliza ampliamente en proyectos iOS para manejo de eventos, animaciones, formato de datos y estrategias de UI.

swift
// 1. Protocol Strategy
protocol PaymentStrategy {
    func pay(amount: Decimal) async throws -> PaymentResult
}

// 2. Concrete Strategies
struct CardPaymentStrategy: PaymentStrategy {
    let cardNumber: String
    let cvv: String

    func pay(amount: Decimal) async throws -> PaymentResult {
        // Enviando solicitud a la API bancaria
        return PaymentResult(status: .success, transactionId: "tx_\(UUID())")
    }
}

struct PayPalPaymentStrategy: PaymentStrategy {
    let email: String

    func pay(amount: Decimal) async throws -> PaymentResult {
        // Redirigir al SDK de PayPal
        return PaymentResult(status: .success, transactionId: "pp_\(UUID())")
    }
}

// 3. Context
class PaymentProcessor {
    private var strategy: PaymentStrategy

    init(strategy: PaymentStrategy) {
        self.strategy = strategy
    }

    func setStrategy(_: PaymentStrategy) {
        strategy = strategy
    }

    func processPayment(amount: Decimal) async throws -> PaymentResult {
        return try await strategy.pay(amount: amount)
    }
}

// Uso
let processor = PaymentProcessor(strategy: CardPaymentStrategy(cardNumber: "4111...", cvv: "123"))
let result = try await processor.processPayment(amount: 99.99)

Strategy en SwiftUI — el patrón se integra naturalmente con MVVM. Un ViewModel contiene una propiedad de estrategia y llama a su método ante una acción del usuario. La View de SwiftUI recibe datos mediante @Published o @State — la estrategia oculta los detalles de implementación de la View. Por ejemplo, una estrategia de validación de texto (emailValidator, phoneValidator) se intercambia según el tipo de campo de entrada. La combinación de Strategy con SwiftUI proporciona flexibilidad sin heredar de UIKit.

Strategy en Android: implementación en Kotlin con Interface

Strategy en Kotlin utiliza Interface a nivel de lenguaje e interfaces funcionales (SAM) para simplificar. Kotlin admite lambdas, lo que permite pasar algoritmos como funciones sin declarar una clase de estrategia separada. En Android, el patrón se usa en ViewModel y Use Cases para aislar algoritmos de carga de datos, caché y manejo de errores. Los proyectos Android con Clean Architecture usan Strategy para inyectar diferentes implementaciones de repositorio según banderas (mock, real, caché).

kotlin
// 1. Interface Strategy
interface PaymentStrategy {
    suspend fun pay(amount: BigDecimal): PaymentResult
}

// 2. Concrete Strategies
class CardPaymentStrategy(
    private val cardNumber: String,
    private val cvv: String
) : PaymentStrategy {
    override suspend fun pay(amount: BigDecimal): PaymentResult {
        // API bancaria mediante Retrofit
        return PaymentResult(success = true, transactionId = "tx_${UUID.randomUUID()}")
    }
}

class PayPalPaymentStrategy(
    private val email: String
) : PaymentStrategy {
    override suspend fun pay(amount: BigDecimal): PaymentResult {
        // Integración con SDK de PayPal
        return PaymentResult(success = true, transactionId = "pp_${UUID.randomUUID()}")
    }
}

// 3. Context
class PaymentProcessor(
    private val strategy: PaymentStrategy
) {
    fun setStrategy(strategy: PaymentStrategy): PaymentProcessor {
        return PaymentProcessor(strategy)
    }

    suspend fun processPayment(amount: BigDecimal): PaymentResult {
        return strategy.pay(amount)
    }
}

// Uso en ViewModel
class CheckoutViewModel : ViewModel() {
    private var processor = PaymentProcessor(CardPaymentStrategy("4111...", "123"))

    fun payWithCard() {
        viewModelScope.launch {
            val result = processor.processPayment(BigDecimal("99.99"))
            // Procesamiento del resultado
        }
    }
}

Strategy con Hilt/Dagger — en proyectos Android, las estrategias a menudo se inyectan mediante DI. Hilt proporciona una implementación concreta de PaymentStrategy a través de @Binds o @Provides. Esto permite cambiar la estrategia sin modificar el código del contexto — simplemente cambie el módulo DI para otra compilación (debug/release). Por ejemplo, se inyecta MockPaymentStrategy para depuración, una estrategia bancaria real para producción. La combinación de Strategy + DI proporciona la máxima flexibilidad.

Comparación de Strategy con State, Command y Template Method

Strategy vs State — estructuralmente los patrones son idénticos: ambos usan composición con una interfaz y clases concretas. La diferencia está en el propósito: Strategy selecciona un algoritmo independiente, State controla el comportamiento del objeto según su estado. En State, el propio contexto cambia la estrategia cuando cambia el estado; en Strategy, el contexto no controla el cambio — el cliente establece explícitamente el algoritmo. Las estrategias no se conocen entre sí, mientras que los estados pueden transicionar entre sí.

Strategy vs Command — Command encapsula una sola acción como objeto, Strategy encapsula un conjunto de algoritmos intercambiables. Command es "qué hacer" (una sola llamada execute), Strategy es "cómo hacerlo" (un algoritmo de varios pasos). Command se usa para colas, ejecución diferida, deshacer/rehacer. Strategy se usa para elegir cómo realizar una tarea en tiempo de ejecución. Los comandos pueden ser parametrizados con estrategias, combinando ambos patrones.

CaracterísticaStrategyStateCommandTemplate Method
PropósitoAlgoritmos intercambiablesComportamiento según estadoEncapsulación de solicitudEsqueleto de algoritmo
CambioExplícitamente por el clienteAutomáticamente por el contextoPor el cliente o colaPor herencia
NivelObjeto (composición)Objeto (composición)ObjetoClase (herencia)

Strategy vs Template Method — ambos patrones definen algoritmos pero de diferentes maneras. Template Method usa herencia: una clase base define el esqueleto del algoritmo (método de plantilla), las subclases sobrescriben pasos individuales. Strategy usa composición: el algoritmo está completamente externalizado a una clase separada. Template Method es más simple para casos con una estructura de algoritmo fija, Strategy — cuando los algoritmos son completamente diferentes y pueden cambiar dinámicamente.

Ejemplos reales de uso del patrón Strategy

Procesamiento de pagos — el ejemplo clásico de Strategy. El carrito de compras de una tienda online contiene una lista de artículos, y el método de pago es elegido por el usuario. Cada método (tarjeta, PayPal, Apple Pay, Google Pay, criptomoneda) es una estrategia separada con una firma común pay(amount). El contexto PaymentProcessor no sabe cómo se procesa exactamente el pago — llama al método común. Añadir un nuevo método de pago no requiere modificar el código del carrito.

Validación de datos — Strategy se usa para diferentes reglas de validación del mismo campo. EmailValidatorStrategy, PhoneValidatorStrategy, AgeValidatorStrategy implementan una interfaz común ValidationStrategy con el método validate(input). Un formulario de registro usa un conjunto de estrategias para verificar cada campo. Las estrategias de validación se pueden combinar en una cadena (Chain of Responsibility) o aplicarse todas a la vez en un bucle. Esto reemplaza largas comprobaciones if-else con una colección de validadores polimórficos.

swift
// Estrategia de ordenamiento
protocol SortingStrategy {
    func sort<T>(_ items: [T]) -> [T] where T: Comparable
}

struct QuickSortStrategy: SortingStrategy {
    func sort<T>(_ items: [T]) -> [T] { /* quicksort */ items }
}

struct MergeSortStrategy: SortingStrategy {
    func sort<T>(_ items: [T]) -> [T] { /* mergesort */ items }
}

class SortedDataSource<T> {
    private var strategy: SortingStrategy
    func display(_ items: [T]) { let sorted = strategy.sort(items) }
}

Autenticación — en aplicaciones móviles, las estrategias de autenticación se cambian según el proveedor. AuthStrategy con los métodos login(), logout(), getToken() se implementa para EmailPasswordAuth, GoogleAuth, AppleAuth, BiometricAuth. El contexto AuthManager acepta la estrategia mediante DI o fábrica. Esto permite añadir nuevos proveedores de autenticación sin modificar la pantalla de inicio de sesión. El patrón Strategy es la base de muchas bibliotecas OAuth y Firebase Authentication.

Preguntas frecuentes

¿Cuándo debo usar Strategy en lugar de if-else?

Strategy está justificado cuando tienes 3+ algoritmos que pueden cambiar o expandirse. Si hay 2 algoritmos y son estables — un simple if-else es menos costoso. Usa Strategy cuando los algoritmos se usan en diferentes partes de la aplicación, cuando necesitas intercambiar algoritmos en tiempo de ejecución, o cuando cada algoritmo requiere sus propias dependencias y pruebas.

¿Es Strategy lo mismo que State?

No, son patrones diferentes con una estructura similar. Strategy — el cliente selecciona explícitamente un algoritmo, y las estrategias son independientes. State — el objeto mismo cambia su comportamiento cuando su estado interno cambia, y los estados pueden transicionar entre sí. En State, el contexto gestiona los cambios de estado; en Strategy, lo hace el código del cliente.

¿Se puede usar Strategy sin clases — mediante closures?

Sí, en Swift y Kotlin una estrategia se puede pasar como closure o lambda. Swift: typealias PaymentHandler = (Decimal) async throws -> PaymentResult. Kotlin: typealias PaymentFun = suspend (BigDecimal) -> PaymentResult. Esto simplifica el código para casos simples pero pierde nombramiento y documentación. Para 1-2 algoritmos, un closure es suficiente; para 4+, es mejor usar clases separadas.

¿Cómo probar el patrón Strategy?

Cada estrategia se prueba con una prueba unitaria separada usando dependencias mock. El Context se prueba con una estrategia mock — verificando que el contexto llama al método de la estrategia y pasa los parámetros correctos. En Swift, usa XCTest + protocolos para mocks; en Kotlin, usa MockK o Mockito. La principal ventaja: cada estrategia se prueba de forma aislada sin configuración compleja.

¿Es Strategy un patrón GoF?

Sí, Strategy es uno de los 23 patrones descritos en el libro "Design Patterns: Elements of Reusable Object-Oriented Software" (Gamma, Helm, Johnson, Vlissides, 1994). Pertenece al grupo de patrones de comportamiento. Alias: Policy. El código de ejemplo original en Smalltalk-80 está disponible en la edición original de GoF.

Resumen

  • Strategy — un patrón de comportamiento para algoritmos intercambiables con una interfaz común
  • Encapsulación — cada algoritmo está aislado en una clase de estrategia separada
  • iOS Swift — implementación mediante Protocol, estructuras y closures
  • Android Kotlin — implementación mediante Interface, lambdas y DI con Hilt
  • Principio Open/Closed — las nuevas estrategias se añaden sin modificar el contexto
  • Aplicaciones — pagos, validación, ordenamiento, autenticación, formato

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también