Pattern Template Method
Fa parte della sezione Programmazione orientata agli oggetti del percorso Dart di Coddy. Lezione 97 di 110.
Il pattern Template Method definisce lo scheletro di un algoritmo in una classe base, consentendo alle sottoclassi di sovrascrivere passaggi specifici senza modificare la struttura complessiva. La classe base controlla il flusso di lavoro, mentre le sottoclassi personalizzano i singoli passaggi.
Questo schema utilizza l’ereditarietà: una classe astratta definisce un metodo modello che richiama una sequenza di passaggi, alcuni dei quali sono astratti (devono essere implementati dalle sottoclassi) e altri hanno implementazioni predefinite:
abstract class DataProcessor {
// Metodo template - definisce la struttura dell'algoritmo
void process() {
readData();
processData();
saveData();
}
void readData(); // Astratto - le sottoclassi devono implementarlo
void processData(); // Astratto - le sottoclassi devono implementarlo
void saveData() { // Implementazione predefinita
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();
// Lettura del file CSV
// Analisi delle righe CSV
// Dati salvati nel database
var json = JsonProcessor();
json.process();
// Lettura del file JSON
// Analisi degli oggetti JSON
// Salvato nell'archivio cloud
}Il metodo process() è il modello: definisce l’ordine delle operazioni. Le sottoclassi implementano readData() e processData() in modo diverso e possono, facoltativamente, sovrascrivere saveData(). Il vantaggio principale è che la struttura dell’algoritmo rimane coerente in tutte le implementazioni, consentendo al contempo flessibilità nei singoli passaggi.
Sfida
FacileCostruiamo un sistema di generazione di report usando il pattern Template Method! Creerai un framework in cui diversi tipi di report seguono la stessa struttura generale, ma ogni tipo di report personalizza passaggi specifici come la raccolta dei dati e la formattazione dell'output.
Organizzerai il codice in due file:
report_generator.dart: questo file contiene la classe base astratta e le implementazioni concrete dei report. Crea una classe astrattaReportGeneratorcon un metodo template chiamatogenerate()che definisce il flusso di generazione del report in quest'ordine:fetchData(),analyzeData(),formatReport()edeliver(). I metodifetchData()eformatReport()devono essere astratti (ogni tipo di report li gestisce in modo diverso), mentreanalyzeData()deve stampareAnalyzing data...edeliver()deve stampareReport delivered via email.come implementazioni predefinite. Poi crea due classi concrete per i report:SalesReport- il suofetchData()stampaFetching sales data from database...e il suoformatReport()stampaFormatting as bar charts and tables.InventoryReport- il suofetchData()stampaFetching inventory levels from warehouse..., il suoformatReport()stampaFormatting as inventory list.e sovrascrivedeliver()per stampareReport sent to warehouse manager.
main.dart: importa il file del generatore di report e mostra come il pattern Template Method mantiene coerente la struttura dell'algoritmo consentendo al contempo la personalizzazione. Crea unSalesReporte chiama il suo metodogenerate(). Poi stampa una riga vuota come separazione. Crea anche unInventoryReporte chiama il suo metodogenerate().
Nota come entrambi i report seguano lo stesso processo in quattro passaggi, ma ciascuno personalizzi i passaggi rilevanti per il proprio scopo specifico. InventoryReport sovrascrive persino il metodo di consegna predefinito per inviare i report a un destinatario diverso!
Output previsto:
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.Provalo tu
import 'report_generator.dart';
void main() {
// TODO: Crea un SalesReport e chiama il suo metodo generate()
// TODO: Stampa una riga vuota per separare
// TODO: Crea un InventoryReport e chiama il suo metodo generate()
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione orientata agli oggetti
File esterniLibrerie e importazioniIntroduzione alla programmazione orientata agli oggettiClassi e oggettiLa parola chiave thisMetodiVariabili di istanzaFondamenti dei costruttoriRiepilogo - Calcolatrice semplice4Sicurezza dei valori null
Introduzione alla sicurezza dei valori nullNullable e non nullableGli operatori ? e !La keyword late e la sicurezza dei valori nullOperatori null-awareSicurezza dei valori null nelle classiRiepilogo - Sistema di profili utente7Classi astratte e interfacce
Classi astratteMetodi astrattiInterfacce in DartInterfacce impliciteImplementare vs estendereInterfacce multipleRiepilogo - Calcolatore di forme10Collezioni e generici
Panoramica di List, Set e MapCollezioni sicure rispetto ai tipiClassi genericheMetodi genericiVincoli sui genericiIterable e IteratorRiepilogo - Archiviazione generica13Concetti avanzati di OOP
Composizione vs ereditarietàMetodi di estensioneClassi chiamabiliClassi sealed (Dart 3)Record (Dart 3)Pattern e matching (3.0)Enum con metodi16Progetto: Gestione della biblioteca
Panoramica del progettoClassi Libro e Utente2I costruttori in Dart
Costruttore predefinitoCostruttori con nomeListe di inizializzazioneCostruttori costantiCostruttori factoryCostruttori di reindirizzamentoRiepilogo - Crea forme5Incapsulamento
Membri pubblici e privatiConvenzione del prefisso _Visibilità a livello di libreriaApprofondimento su getter e setterNascondimento delle informazioniRiepilogo - Registri degli studenti8Mixin
Introduzione ai MixinCreare MixinUsare più MixinParola chiave on nei MixinMixin vs ereditarietàMixin vs interfacciaRiepilogo - Sistema animale11Metodi speciali
Sovrascrittura di toString()Sovrascrittura di hashCode e ==Interfaccia ComparableMetodo call()Sovrascrittura di noSuchMethodRiepilogo - Collezione personalizzata14Modelli di progettazione Parte 1
Introduzione ai modelli di progettazioneSingletonFactoryObserverStrategy3Proprietà delle classi
Membri di istanza e staticiCampi final e constVariabili lateMetodi e campi staticiGetter e setterRiepilogo - Gestore di conti bancari6Ereditarietà
Ereditarietà di baseLa parola chiave superOverride dei metodiL’annotazione @overrideLa parola chiave final per le classiCostruttori ed ereditarietàRiepilogo - Gerarchia dei dipendenti9Polimorfismo
Fondamenti di polimorfismoPolimorfismo tramite interfacceControllo del tipo a runtimeGli operatori is e asParola chiave covariantRiepilogo - Elaboratore di pagamenti12OOP asincrona
Future e async/awaitNozioni di base sugli streamController degli streamCostruttori asincroniAsync nei metodi di classeRiepilogo - Recupero dei dati15Pattern di progettazione Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositePattern RepositoryEsercitati da solo: Compilatore Dart online