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, lo que permite 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 pasos individuales.
Este patrón utiliza la herencia: una clase abstracta define un método plantilla que llama a una secuencia de pasos, algunos de los cuales son abstractos (deben ser implementados por las subclases) y otros tienen implementaciones predeterminadas:
abstract class DataProcessor {
// Método 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 redefinir saveData(). El beneficio principal es que la estructura del algoritmo se mantiene coherente en todas las implementaciones, al tiempo que permite flexibilidad en los pasos individuales.
Desafío
Fácil¡Construyamos un sistema de generación de informes usando el patrón Template Method! Crearás un marco en el que diferentes tipos de informes siguen la misma estructura general, pero cada tipo de informe personaliza pasos específicos, como recopilar datos y dar formato a 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 base abstractaReportGeneratorcon un método plantilla llamadogenerate()que define el flujo de trabajo de generación del informe en este orden:fetchData(),analyzeData(),formatReport()ydeliver(). Los métodosfetchData()yformatReport()deben ser abstractos (cada tipo de informe los gestiona de forma diferente), mientras queanalyzeData()debe imprimirAnalyzing data...ydeliver()debe imprimirReport delivered via email.como implementaciones predeterminadas. Después, crea dos clases concretas de informes:SalesReport: su métodofetchData()imprimeFetching sales data from database...y su métodoformatReport()imprimeFormatting as bar charts and tables.InventoryReport: su métodofetchData()imprimeFetching inventory levels from warehouse..., su métodoformatReport()imprimeFormatting as inventory list.y sobrescribedeliver()para imprimirReport sent to warehouse manager.
main.dart: Importa tu archivo del generador de informes y demuestra cómo el patrón Template Method mantiene coherente la estructura del algoritmo a la vez que permite la personalización. Crea unSalesReporty llama a su métodogenerate(). Después, imprime una línea vacía como 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 relevantes para su propósito específico. ¡InventoryReport incluso sobrescribe el método de entrega predeterminado para enviar los 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.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 separación
// 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 RepositoryPractica por tu cuenta: Compilador de Dart online