Patrón Template Method
Parte de la sección Programación Orientada a Objetos del Journey de Dart de Coddy — lección 97 de 110.
El patrón Template Method define el esqueleto de un algoritmo en una clase base, permitiendo que las subclases sobrescriban pasos específicos sin cambiar la estructura general. La clase base controla el flujo de trabajo, mientras que las subclases personalizan los pasos individuales.
Este patrón utiliza la herencia: una clase abstracta define un método de plantilla que llama a una secuencia de pasos, algunos de los cuales son abstractos (deben ser implementados por las subclases) y otros tienen implementaciones por defecto:
abstract class DataProcessor {
// Método de plantilla - define la estructura del algoritmo
void process() {
readData();
processData();
saveData();
}
void readData(); // Abstracto - las subclases deben implementar
void processData(); // Abstracto - las subclases deben implementar
void saveData() { // Implementación por defecto
print('Data saved to database');
}
}
class CsvProcessor extends DataProcessor {
@override
void readData() => print('Reading CSV file');
@override
void processData() => print('Parsing CSV rows');
}
class JsonProcessor extends DataProcessor {
@override
void readData() => print('Reading JSON file');
@override
void processData() => print('Parsing JSON objects');
@override
void saveData() => print('Saved to cloud storage');
}
void main() {
var csv = CsvProcessor();
csv.process();
// Leyendo archivo CSV
// Analizando filas CSV
// Datos guardados en la base de datos
var json = JsonProcessor();
json.process();
// Leyendo archivo JSON
// Analizando objetos JSON
// Guardado en almacenamiento en la nube
}El método process() es la plantilla: define el orden de las operaciones. Las subclases implementan readData() y processData() de manera diferente, y opcionalmente pueden sobrescribir saveData(). El beneficio clave es que la estructura del algoritmo se mantiene consistente en todas las implementaciones, al tiempo que permite flexibilidad en los pasos individuales.
Desafío
Fácil¡Vamos a construir un sistema de generación de informes utilizando el patrón Template Method! Crearás un marco de trabajo donde diferentes tipos de informes siguen la misma estructura general, pero cada tipo de informe personaliza pasos específicos como la recopilación de datos y el formateo de la salida.
Organizarás tu código en dos archivos:
report_generator.dart: Este archivo contiene tu clase base abstracta y las implementaciones concretas de los informes. Crea una clase abstractaReportGeneratorcon un método de plantilla llamadogenerate()que defina el flujo de trabajo de generación de informes en este orden:fetchData(),analyzeData(),formatReport()ydeliver(). Los métodosfetchData()yformatReport()deben ser abstractos (cada tipo de informe los maneja de manera diferente), mientras queanalyzeData()debe imprimirAnalyzing data...ydeliver()debe imprimirReport delivered via email.como implementaciones por defecto. Luego crea dos clases de informes concretas:SalesReport- sufetchData()imprimeFetching sales data from database...y suformatReport()imprimeFormatting as bar charts and tables.InventoryReport- sufetchData()imprimeFetching inventory levels from warehouse..., suformatReport()imprimeFormatting as inventory list., y sobrescribedeliver()para imprimirReport sent to warehouse manager.
main.dart: Importa tu archivo de generador de informes y demuestra cómo el patrón Template Method mantiene la estructura del algoritmo consistente mientras permite la personalización. Crea unSalesReporty llama a su métodogenerate(). Luego imprime una línea vacía para separación. Crea unInventoryReporty llama también a su métodogenerate().
Observa cómo ambos informes siguen el mismo proceso de cuatro pasos, pero cada uno personaliza los pasos que importan para su propósito específico. ¡El InventoryReport incluso sobrescribe el método de entrega por defecto para enviar informes a un destinatario diferente!
Salida esperada:
Fetching sales data from database...
Analyzing data...
Formatting as bar charts and tables.
Report delivered via email.
Fetching inventory levels from warehouse...
Analyzing data...
Formatting as inventory list.
Report sent to warehouse manager.Hoja de referencia
El patrón Template Method define el esqueleto de un algoritmo en una clase base, permitiendo que las subclases sobrescriban pasos específicos sin cambiar la estructura general.
Una clase abstracta define un método de plantilla que llama a una secuencia de pasos. Algunos pasos son abstractos (deben ser implementados por las subclases) y otros tienen implementaciones por defecto:
abstract class DataProcessor {
// Método de plantilla - define la estructura del algoritmo
void process() {
readData();
processData();
saveData();
}
void readData(); // Abstracto - las subclases deben implementar
void processData(); // Abstracto - las subclases deben implementar
void saveData() { // Implementación por defecto
print('Data saved to database');
}
}
class CsvProcessor extends DataProcessor {
@override
void readData() => print('Reading CSV file');
@override
void processData() => print('Parsing CSV rows');
}
class JsonProcessor extends DataProcessor {
@override
void readData() => print('Reading JSON file');
@override
void processData() => print('Parsing JSON objects');
@override
void saveData() => print('Saved to cloud storage');
}
El método de plantilla controla el orden del flujo de trabajo. Las subclases personalizan pasos individuales implementando métodos abstractos y, opcionalmente, sobrescribiendo las implementaciones por defecto. La estructura del algoritmo se mantiene consistente en todas las implementaciones.
Pruébalo tú mismo
import 'report_generator.dart';
void main() {
// TODO: Crea un SalesReport y llama a su método generate()
// TODO: Imprime una línea vacía para separar
// TODO: Crea un InventoryReport y llama a su método generate()
}
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 POO
Archivos externosLibrerías e importacionesIntroducción a la POOClases vs. ObjetosLa palabra clave thisMétodosVariables de instanciaConceptos básicos de constructoresResumen - Calculadora sencilla4Seguridad de nulos
Introducción a la seguridad de nulosNulables vs No nulablesLos operadores ? y !Palabra clave Late y Null SafetyOperadores Null-awareNull Safety en clasesResumen - Sistema de perfil de usuario7Clases abstractas e interfaces
Clases abstractasMétodos abstractosInterfaces en DartInterfaces implícitasImplementar vs. ExtenderInterfaces múltiplesRepaso - Calculadora de figuras10Colecciones y Genéricos
Visión general de List, Set y MapColecciones con seguridad de tiposClases genéricasMétodos genéricosRestricciones genéricasIterable e IteratorResumen - Almacenamiento genérico2Constructores en Dart
Constructor por defectoConstructores nombradosListas de inicializaciónConstructores constantesConstructores de fábricaConstructores de redireccionamientoResumen - Constructor de formas5Encapsulamiento
Miembros públicos vs. privadosLa convención del prefijo _Privacidad a nivel de libreríaProfundidad en Getters y SettersOcultamiento de informaciónResumen - Registros de estudiantes8Mixins
Introducción a los MixinsCreación de MixinsUso de múltiples MixinsPalabra clave on en MixinsMixin vs HerenciaMixin vs InterfazResumen - Sistema Animal11Métodos especiales
Sobrescritura de toString()Sobrescritura de hashCode y ==Interfaz ComparableMétodo call()Sobrescritura de noSuchMethodResumen - Colección personalizada14Patrones de diseño Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón Strategy3Propiedades de clase
Miembros de instancia vs. estáticosCampos Final y ConstVariables LateMétodos y campos estáticosGetters y SettersResumen - Gestor de cuentas bancarias6Herencia
Herencia básicaLa palabra clave superSobrescritura de métodosLa anotación @overrideLa palabra clave final en clasesConstructores y herenciaResumen - Jerarquía de empleados9Polimorfismo
Fundamentos del polimorfismoPolimorfismo mediante interfacesComprobación de tipos en tiempo de ejecuciónLos operadores is y asPalabra clave covariantResumen - Procesador de pagos12POO Asíncrona
Futures y async/awaitFundamentos de StreamsStream ControllersConstructores asíncronosAsincronía en métodos de claseRepaso - Data Fetcher15Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Repository