¿Alguna vez has copiado y pegado lógica similar en cada clase hasta pensar: «Algo va mal»? Al copiar por tercera vez el código de carga de datos por pantalla en una app de iOS, cualquiera se detiene.
En estos casos, la herramienta que conviene sacar del cajón es el patrón Template Method.
En resumen: fija el flujo completo —la estructura— en un solo lugar y deja que cada implementación complete únicamente los pasos variables. En Swift, las extensiones de protocolos permiten hacerlo de forma mucho más limpia que la herencia.
En este artículo veremos qué es el patrón Template Method, por qué en Swift las extensiones de protocolos se acercan a la solución ideal y cómo construir la estructura con código real.
Veamos primero el resumen clave
- El patrón Template Method separa «procedimientos fijos + pasos intercambiables».
- Tradicionalmente se implementa mediante herencia de una clase base, pero en Swift conviene usar extensiones de protocolos.
- La estructura queda en la implementación predeterminada de la extensión y las partes variables, como requisitos del protocolo.
- Te libera de las limitaciones de la herencia: herencia única y acoplamiento fuerte.
¿Qué es el patrón Template Method?
El nombre suena grandilocuente, pero el concepto es sencillo.
Piensa en una receta. El orden «preparar ingredientes → acondicionar → cocinar → emplatar» es fijo.
Pero los ingredientes y la forma de cocinarlos cambian según el plato.
Aquí, el orden —la estructura— es el método plantilla, y cada paso que cambia según el plato es la parte intercambiable.
Controla el flujo en un solo lugar y delega fuera únicamente la implementación detallada.
Puedes considerar esta frase el patrón Template Method completo.
En código, la situación es esta: el procedimiento para cargar datos es igual en cualquier pantalla. Iniciar la carga → realizar la solicitud → analizar → actualizar la pantalla.
Lo único que cambia es «qué URL solicitar» y «cómo analizar los datos recibidos».
Reescribir este procedimiento común cada vez era un desperdicio.
¿Por qué usar una extensión de protocolo en Swift en lugar de herencia?
El enfoque original coloca la estructura en una clase base y hace que la subclase solo sobrescriba determinados métodos. Es el enfoque de los libros de texto de Java.
Sin embargo, implementarlo mediante herencia de clases en Swift tiene varias desventajas.
- Las clases solo admiten herencia única. Si ya heredas de una clase, no hay más opciones.
- Además, no puedes usarlo con structs ni enums.
- La relación entre clase base y subclase crea un acoplamiento fuerte y dificulta cambiar la implementación después.
Las extensiones de protocolos resuelven la mayoría de estos problemas.
Proporcionas el método estructural como implementación predeterminada de la extensión y declaras los pasos variables únicamente como requisitos del protocolo.
Así, tanto un struct como una clase que adopte el protocolo obtiene gratis la estructura común, sin las restricciones de la herencia.
Este es un ejemplo de cómo modelar el procedimiento de carga de datos con un protocolo. load() es la estructura fija y los otros dos elementos son las partes intercambiables.
protocol DataLoadable {
associatedtype Item
var endpoint: URL { get } // Difiere según la pantalla
func parse(_ data: Data) -> [Item] // Difiere según la pantalla
}
extension DataLoadable {
func load() async throws -> [Item] { // Estructura fija
let (data, _) = try await URLSession.shared.data(from: endpoint)
return parse(data)
}
}
La extensión controla el orden de load().
Cada pantalla solo tiene que implementar endpoint y parse a su manera.
Vamos a completar la estructura en la práctica
Ahora veamos el tipo que adopta este protocolo. Como se trata de adopción y no de herencia, también puede ser un struct.
struct ArticleLoader: DataLoadable {
let endpoint = URL(string: "https://api.example.com/articles")!
func parse(_ data: Data) -> [Article] {
(try? JSONDecoder().decode([Article].self, from: data)) ?? []
}
}
// uso: let articles = try await ArticleLoader().load()
Como puedes ver, ArticleLoader no implementa directamente load().
Aun así, puede llamar a load() porque la extensión proporciona una implementación predeterminada.
Ese es el poder de implementar un Template Method con una extensión de protocolo. Cuando aparece una pantalla nueva, basta con crear otro struct que complete endpoint y parse.
Desde que cambié a este enfoque, el código necesario para añadir pantallas se redujo a menos de la mitad. Al centralizar la carga y el manejo de errores, también resulta mucho más fácil corregir errores.
Un detalle importante: la implementación predeterminada de una extensión de protocolo funciona de forma algo distinta a override. Aunque el tipo adoptante defina un método con el mismo nombre, si no está declarado como requisito del protocolo, puede invocarse de forma inesperada mediante despacho estático.
Por eso, es más seguro declarar siempre los pasos intercambiables como requisitos en el cuerpo del protocolo.
Preguntas y respuestas breves
P. Entonces, ¿ya no hace falta usar el Template Method basado en herencia?
En lugares con una jerarquía de clases ya establecida, como UIKit, sobrescribir mediante herencia puede ser lo más natural. Elige según la situación.
P. associatedtype me resulta complicado.
Si el tipo de retorno es fijo, puedes definirlo simplemente como protocolo sin associatedtype. Úsalo solo cuando necesites genéricos.
Al construir la estructura con una extensión de protocolo, todo el esfuerzo que suponía lidiar con la herencia queda casi reducido a nada.
Si tienes lógica duplicada mediante copiar y pegar, extrae hoy aunque solo sea una parte a un protocolo. La diferencia se nota enseguida. ¡Ánimo!

