Menu
Coddy logo textTech

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.

challenge icon

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 abstracta ReportGenerator con un método de plantilla llamado generate() que defina el flujo de trabajo de generación de informes en este orden: fetchData(), analyzeData(), formatReport() y deliver(). Los métodos fetchData() y formatReport() deben ser abstractos (cada tipo de informe los maneja de manera diferente), mientras que analyzeData() debe imprimir Analyzing data... y deliver() debe imprimir Report delivered via email. como implementaciones por defecto. Luego crea dos clases de informes concretas:
    • SalesReport - su fetchData() imprime Fetching sales data from database... y su formatReport() imprime Formatting as bar charts and tables.
    • InventoryReport - su fetchData() imprime Fetching inventory levels from warehouse..., su formatReport() imprime Formatting as inventory list., y sobrescribe deliver() para imprimir Report 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 un SalesReport y llama a su método generate(). Luego imprime una línea vacía para separación. Crea un InventoryReport y llama también a su método generate().

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()
}
quiz iconPonte a prueba

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