Table of Contents
La gestión de múltiples métodos de pago es uno de los aspectos más difíciles de construir una aplicación móvil. Cada método de pago —ya sea con tarjetas de crédito, PayPal, Apple Pay, Google Pay o carteras específicas de la región como Alipay y WeChat Pay— se ajusta a su propia API, reglas de validación, manejo de errores y requisitos de cumplimiento.
El patrón de fábrica ofrece una solución estructurada a esta complejidad. Al centralizar la creación de objetos de método de pago, decodifica el código cliente de las implementaciones concretas de pagos. Esto hace que su aplicación sea más sostenible, testable y listo para escalar como nuevas opciones de pago inevitablemente aparecen.
En este artículo, exploraremos cómo aplicar el patrón de fábrica para gestionar diferentes métodos de pago en aplicaciones móviles, con ejemplos prácticos y mejores prácticas. También discutiremos cómo este patrón se alinea con arquitecturas modernas como MVVM y Clean Architecture, y cómo puede integrarlo con servicios de backend como Directus para almacenar y recuperar configuraciones de pago dinámicamente.
Comprender el patrón de fábrica
El patrón de fábrica es un patrón de diseño creacional que proporciona una interfaz para crear objetos en una superclase, pero permite que subclases alteren el tipo de objetos que se crearán. En términos más simples, encapsula la lógica de instantáneas para que los clientes no necesitan conocer las clases de hormigón; sólo interactúan con una interfaz común.
Este patrón es especialmente valioso en aplicaciones móviles donde el conjunto de métodos de pago puede crecer con el tiempo. Sin una fábrica, usted podría terminar con grandes o declaraciones dispersas en su base de código, cada uno sabiendo cómo construir un método de pago específico. Ese enfoque viola el Principio Abierto/Cerrado y hace que el código rígido — la inclusión de un nuevo método de pago requiere modificar cada lugar que crea uno.
El patrón de fábrica resuelve esto colocando toda lógica de creación en un solo lugar. Cuando se introduce un nuevo método de pago, simplemente agrega una nueva clase de hormigón y actualiza el método de fábrica. El resto de su aplicación permanece inalterable.
Cómo funciona el patrón de fábrica
El patrón normalmente implica tres participantes:
- Producto] – Una interfaz o clase abstracta que define las operaciones todos los métodos de pago deben apoyar (por ejemplo, , ).
- Productos de hormigón ] – Clases que implementan la interfaz de producto para cada método de pago específico (por ejemplo, , ).
- Creador (Factory) – Una clase (o función) que contiene un método para crear productos. El método acepta un parámetro (por ejemplo, una cadena o un enum) y devuelve el producto de hormigón apropiado.
En aplicaciones móviles, esta fábrica es a menudo un soloton o un servicio de inyección de dependencia, lo que facilita el intercambio de implementaciones durante las pruebas o cuando se admiten diferentes configuraciones de aplicaciones.
Por qué los métodos de pago son complejos en aplicaciones móviles
Antes de sumergirse en la implementación, es útil entender los puntos de dolor específicos que el patrón de fábrica aborda. El manejo de pagos en aplicaciones móviles va más allá simplemente llamando a una API.
- Multiple SDKs and APIs] – Cada proveedor de pago ofrece su propia API SDK o REST. Integrarlas directamente en su lógica de negocio crea un acoplamiento estrecho.
- Diferencias normativas y reglamentarias: No se puede permitir un método de pago disponible en un país. Es posible que necesite elegir dinámicamente la configuración de la fábrica basada en la localización del usuario.
- Reglas de validación] – Las tarjetas de crédito requieren cheques de Luhn y validación de fecha de vencimiento; las carteras digitales necesitan manipulación de fichas; los métodos locales pueden hacer cumplir requisitos específicos de campo.
- Manejo de espejos y contratiempos – Cuando un pago falla, la aplicación puede necesitar ofrecer un método alternativo o reingresar con diferentes parámetros. Una fábrica centralizada simplifica esta lógica.
- Testing – No quieres golpear servidores de pago reales durante las pruebas de unidad. El patrón de fábrica permite inyectar objetos de pago de mock fácilmente.
- Configuración dinámica] – Muchas aplicaciones buscan métodos de pago disponibles desde un servidor remoto (por ejemplo, desde Directus). La fábrica puede interpretar esa configuración para crear los objetos adecuados en el tiempo de ejecución.
Dada estos desafíos, una abstracción de pago bien diseñada se vuelve crítica. El patrón de fábrica proporciona esa capa de abstracción.
Aplicación del Patrón de Fábrica para los Métodos de Pago
Caminemos a través de una implementación concreta. Mientras que los ejemplos de código son lingüístico-agnóstico (pseudocode), utilizaremos conceptos que se traducen directamente a Swift, Kotlin, Flutter o React Native.
Paso 1: Definir la interfaz de método de pago
Comience por definir una interfaz común que todos los métodos de pago deben implementar. Esta interfaz debe incluir métodos universales en los tipos de pago, como y .
interface PaymentMethod {
func processPayment(amount: Double, currency: String) -> PaymentResult
func validate() -> Bool
}
También puede incluir propiedades como , , o , que la UI puede utilizar para mostrar opciones de pago.
Paso 2: Crear clases de pago concretas
Para cada método de pago que soporta, cree una clase que implemente la interfaz . Estas clases encapsulan toda la lógica del proveedor.
class CreditCardPayment : PaymentMethod {
private let cardNumber: String
private let expiry: String
private let cvv: String
init(cardNumber: String, expiry: String, cvv: String) {
self.cardNumber = cardNumber
self.expiry = expiry
self.cvv = cvv
}
func validate() -> Bool {
// Luhn check, expiry date > today, etc.
return true // simplified
}
func processPayment(amount: Double, currency: String) -> PaymentResult {
// Call Stripe or Braintree SDK
return PaymentResult.success()
}
}
class PayPalPayment : PaymentMethod {
private let token: String
init(token: String) {
self.token = token
}
func validate() -> Bool {
return !token.isEmpty
}
func processPayment(amount: Double, currency: String) -> PaymentResult {
// Call PayPal SDK
return PaymentResult.success()
}
}
class ApplePayPayment : PaymentMethod {
private let paymentData: Data
init(paymentData: Data) {
self.paymentData = paymentData
}
func validate() -> Bool {
return paymentData.count > 0
}
func processPayment(amount: Double, currency: String) -> PaymentResult {
// Use PassKit or Stripe Apple Pay integration
return PaymentResult.success()
}
}
Observe que cada clase concreta maneja su propia validación y llamadas SDK. El resto de la aplicación no se preocupa por las diferencias, sino que sólo llama .
Paso 3: Construir la clase de fábrica
La clase de fábrica es responsable de crear el objeto apropiado del método de pago basado en parámetros de entrada. La entrada puede provenir de la selección de usuarios, un objeto de configuración o una respuesta del servidor (por ejemplo, de Directus).
class PaymentFactory {
static func createPaymentMethod(type: String, parameters: [String: Any]) -> PaymentMethod? {
switch type {
case "credit_card":
guard let cardNumber = parameters["cardNumber"] as? String,
let expiry = parameters["expiry"] as? String,
let cvv = parameters["cvv"] as? String else {
return nil
}
return CreditCardPayment(cardNumber: cardNumber, expiry: expiry, cvv: cvv)
case "paypal":
guard let token = parameters["token"] as? String else {
return nil
}
return PayPalPayment(token: token)
case "apple_pay":
guard let paymentData = parameters["paymentData"] as? Data else {
return nil
}
return ApplePayPayment(paymentData: paymentData)
default:
return nil
}
}
}
En un escenario más avanzado, puede utilizar un enum en lugar de una cadena para el tipo, o puede cargar la configuración de fábrica de una fuente remota. El punto clave es que la fábrica es el sólo lugar donde las clases de hormigón se instantánean.
Paso 4: Usando la fábrica en su aplicación
Ahora, cuando un usuario selecciona un método de pago y proporciona los detalles necesarios, su modelo de vista o controlador solo necesita llamar a la fábrica:
let paymentType = selectedPaymentMethod.type // "credit_card", "paypal", etc.
let parameters = collectInputParameters()
if let paymentMethod = PaymentFactory.createPaymentMethod(type: paymentType, parameters: parameters) {
paymentMethod.processPayment(amount: total, currency: "USD")
} else {
// show error – unsupported method or invalid input
}
Este código es limpio, testable y abierto para la extensión. Añadiendo un nuevo método de pago (por ejemplo, Google Pay) requiere sólo una nueva clase y un caso adicional en la declaración de la fábrica —no se necesitan otros cambios.
Variaciones de manejo: Factorías país-específicas y dinámicas
En aplicaciones de mundo real, el conjunto de métodos de pago disponibles a menudo cambia según el país del usuario, la versión de la aplicación o las reglas de negocio. Puede hacer que la fábrica sea dinámica alimentando un objeto de configuración.
Suppose you use Directus to store enabled payment methods per region. Your backend returns a JSON object like this:
{
"methods": ["credit_card", "paypal", "apple_pay"],
"paypal": { "environment": "sandbox", "clientId": "abc123" }
}
Puede almacenar esta configuración en un repositorio o en el estado de su aplicación. Entonces la fábrica puede leerla en tiempo de ejecución:
class DynamicPaymentFactory {
private let config: PaymentConfiguration
init(config: PaymentConfiguration) {
self.config = config
}
func createPaymentMethod(type: String, parameters: [String: Any]) -> PaymentMethod? {
guard config.methods.contains(type) else { return nil }
// Use config-specific parameters (e.g., clientId for PayPal)
// ... switch as before
}
}
Este enfoque mantiene su aplicación adaptable sin requerir una nueva versión de la aplicación para cada cambio de proveedor de pago.
Beneficios de usar el patrón de fábrica
Ahora, las ventajas deben ser claras. Vamos a enumerarlas más a fondo.
1. Encapsulación de la creación de objetos
La fábrica centraliza la lógica de instantáneas. Si el constructor de una clase de pago cambia (por ejemplo, se añade un nuevo parámetro requerido), sólo actualiza la fábrica y la clase de hormigón. Todos los calladores permanecen sin afectar.
2. Adherencia al Principio Abierto/Cerrado
Su código está abierto para la extensión (aprobar nuevos métodos de pago) pero cerrado para la modificación (las clases existentes no cambian). Esto reduce el riesgo de introducir errores en los flujos de pago ya probados.
3. Pruebas de unidad simplificadas
Debido a que la fábrica puede ser burlada o reemplazada, puede inyectar fácilmente objetos de pago falsos durante las pruebas. Por ejemplo, puede crear un que siempre devuelve un pago exitoso sin tocar la red.
4. Mejoramiento de la organización del Código
El patrón de fábrica naturalmente grupos de clases relacionadas (métodos de pago) bajo una interfaz común. Esto hace que la base de código sea más fácil de navegar y entender.
5. Flexibilidad en tiempo de ejecución
Puede combinar la fábrica con una estrategia o patrón de plantilla para alterar el comportamiento basado en condiciones de tiempo de ejecución, por ejemplo, elegir entre un entorno de prueba y producción.
6. Escalabilidad
A medida que su aplicación crece para soportar docenas de métodos de pago, el patrón de fábrica escala con gracia. Cada nuevo método es un archivo separado, y el interruptor de fábrica permanece lineal.
Consideraciones reales del mundo
Integración con inyección de dependencia
En arquitecturas móviles modernas (MVVM, Clean Architecture, Viper), la fábrica debe estar registrada en su contenedor de inyección de dependencia. De esta manera, puede inyectar una fábrica real en producción y una fábrica de mock en pruebas. Por ejemplo, usando Dagger en Android o Swinject en iOS:
// Swift with Swinject
container.register(PaymentFactoryProtocol.self) { _ in PaymentFactory() }
Manejo de errores y retrocesos
Su fábrica debe manejar la entrada inválida con gracia. Volver o lanzar un tipo de error específico permite al usuario presentar una interfaz de usuario significativa. De manera similar, usted podría implementar una fábrica de retroceso que se opone a un método de pago universal si el solicitado no se inicializa.
Configuración desde Backend (Directus)
Directus puede ser utilizado para almacenar metadatos de método de pago, como el orden de visualización, campos requeridos, o incluso reglas de validación personalizadas. Su aplicación móvil fetches esta configuración en el inicio y la pasa a la fábrica. Esto decodifica al cliente de la lógica de pago codificada.
Por ejemplo, podría crear una colección en Directus con campos:
- (traer: "credit card", "paypal")
- (cadena)
- (JSON array of field names)
- (boolean)
Su aplicación móvil estrena esta colección a través del SDK Directus y construye dinámicamente el registro de la fábrica. Este patrón permite a los interesados no desarrolladores controlar las ofertas de pago sin cambios en el código.
Las mejores prácticas al utilizar el patrón de fábrica
- Mantén la fábrica simple. Sólo debe crear objetos. Si te encuentras añadiendo lógica comercial (por ejemplo, conversión de divisas), extraiga eso en servicios separados.
- Utilizar la escritura fuerte. Preferir enums o clases selladas sobre cadenas para el tipo de método. Esto evita que los errores de tiempo de ejecución de identificadores desperdiciados y le da soporte para el compilador.
- Documentar la interfaz.] Asegurar que todos los miembros de la interfaz tengan contratos claros. ¿Qué hace exactamente? ¿ lanza o devuelve un error?
- Prueba la fábrica por separado. Escribe pruebas de unidad que verifican que la fábrica devuelve la clase de hormigón correcta para cada entrada, y que devuelve nil para tipos no soportados.
- Combine con otros patrones. La fábrica funciona bien con el patrón de estrategia (para manejar diferentes flujos de pago) y el patrón de Builder (si un método de pago requiere una configuración compleja).
- Considera un registro. En lugar de un interruptor monolítico, puede crear un registro abierto donde las clases de método de pago se registran. Esto es común en las arquitecturas de plugin.
Conclusión
Gestionar múltiples métodos de pago en aplicaciones móviles no tiene que ser una fuente de deuda técnica. Al aplicar el patrón de fábrica, usted encapsula la complejidad de la creación de objetos, haciendo su limpiador de códigos, más testable, y listo para la expansión futura. El patrón respeta el principio abierto/Closed, decouples lógica de negocios de SDKs de terceros, e integra sin problemas con arquitecturas modernas y servicios de backend como Directus.
Cuando se enfrenta a una lista creciente de opciones de pago, llegar al patrón de fábrica. Le ahorrará tiempo, reducirá los errores, y le permitirá añadir nuevos métodos de pago con confianza.
] ]Patrón de Métodos de Fragilidad (Wikipedia)
Iniciar el pago de la huelga: integración móvil] [Recopilación de datos] [FLT]