Un Template Method Pattern è uno schema progettuale di tipo comportamentale (Behavioral Design Pattern), diffuso nell’Object Oriented Programming, che consente di stabilire la struttura di un algoritmo di classe, inteso come procedura per la soluzione di problematiche ricorrenti, facendo in modo che le sue classi secondarie (derivate o sottoclassi) possano effettuare arbitrariamente delle parziali implementazioni atte a personalizzare per ridefinizione i comportamenti previsti, il tutto senza la necessità di riproporre nuovamente le medesime porzioni di codice sorgente; si tratta quindi di un Design Pattern che potrebbe rivelarsi particolarmente utile per evitare l’appesantimento del listato a causa dei fenomeni di ridondanza e di duplicazione.
Nel corso di questa trattazione verrà proposto un esempio di utilizzo pratico basato su PHP del pattern in oggetto.
Funzionamento del Template Method Pattern
Nel caso specifico del linguaggio PHP, si avrà all'interno del Template Method Pattern un classe astratta, cioè un classe sviluppata soltanto parzialmente i cui metodi potranno essere implementati dalle classi secondarie, a cui sarà associato il compito di definire un metodo correlato ad un algoritmo e i metodi impiegati dall'algoritmo stesso; l’uso di questi ultimi non dovrà essere necessariamente richiesto, ma come impostazione predefinita i metodi facoltativi non eseguiranno alcuna operazione.
Nella Programmazione Orientata agli Oggetti accade infatti abbastanza frequentemente di dover gestire diverse sottoclassi che ereditano da una stessa classe principale, una condizione di per se non negativa ma che può presentare l’inconveniente di dover implementare strutture estremamente simili; una possibile soluzione potrebbe suggerire allo sviluppatore di ridefinire il sorgente della propria applicazione in modo che il peso di eventuali duplicazioni possa essere spostato dalla moltitudine delle classi secondarie alla singola superclasse, i metodi comuni faranno così riferimento direttamente alla classe principale.
Si tratta a ben vedere di una semplice tecnica di deferimento, si pensi per esempio di dover gestire un’applicazione complessa che comprenda più parti interconnesse tra di loro ma che debba prevedere delle modifiche che non coinvolgano l’intera struttura, una modalità di intervento in sede di sviluppo potrebbe essere quella di fare in modo che le sottoclassi possano agire per delega su parti dell’algoritmo di una classe astratta; il Template Method Pattern consente proprio questo, cioè la descrizione della struttura di base di un algoritmo in un’operazione lasciando alle classi secondarie la libertà di eseguire eventuali implementazioni.
Struttura del Template Method Pattern
Come anticipato, uno struttura tipica del Template Method Pattern prevede una classe astratta, che prenderà il nome di AbstractClass e da un numero variabile di sottoclassi dette “concrete” (ConcreteClass) che svolgeranno il ruolo di estendere l’astratta tramite ereditarietà; in questo caso però non sono le classi derivate a richiamare i metodi della superclasse, ma il metodo template della principale, cioè la struttura di base dell’algoritmo, a richiamare quelli implementati nelle secondarie.
In generale il template può presentare istruzioni e chiamate ad ulteriori metodi come per esempio:
- primitive operations concepite per essere ridefinite nelle classi derivate;
- hooks, cioè metodi opzionalmente ridefinibili o ereditabili nella loro forma originale;
- metodi non sottoponibili a overridding perché già definitivi in superclasse.
Un semplice esempio di utilizzo potrebbe essere quello che prevede di creare una AbstractClass contenente un metodo template associato all'algoritmo per la definizione del contenuto strutturale di una file; ora, a questo scopo si potrebbe concepire una superclasse recante i metodi per la strutturazione di un file HTML, di un XML e così via, in alternativa il Template Method Pattern consentirà di definire un modello generico che poi verrà liberamente implementato dalle sottoclassi a seconda del tipo di file che si desidera definire.
Dalla definizione dell’Abstract all’implementazione nelle sottoclassi
Per mostrare un esempio pratico di utilizzo del Template Method Pattern è possibile proporre una piccola applicazione in cui una superclasse, denominata TemplateBase, integra un metodo (visualizzaMessaggioCompleto()
) che richiama i metodi estraiOggetto()
e estraiTesto()
:
<?php // definizione della superclasse come classe astratta abstract class TemplateBase { // metodo e struttura dell’algoritmo di classe public final function visualizzaMessaggioCompleto($messaggio) { $bozza_oggetto = $messaggio->estraiOggetto(); $bozza_testo = $messaggio->estraiTesto(); $oggetto_definitivo = $this->correggiOggetto($bozza_oggetto); $testo_definitivo = $this->correggiTesto($bozza_testo); if (NULL == $testo_definitivo) { $messaggio_visualizzato = $oggetto_definitivo; } else { $messaggio_visualizzato = $oggetto_definitivo." .:::. ".$testo_definitivo; } return $messaggio_visualizzato; } // funzione per l’overriding abstract function correggiOggetto($bozza_oggetto); // hook function correggiTesto($bozza_testo) { return NULL; } } /* ereditarietà delle sottoclassi*/ // prima ConcreteClass class TemplateConTesto extends TemplateBase { function correggiOggetto($bozza_oggetto) { return str_replace(" ","---",$bozza_oggetto); } function correggiTesto($bozza_testo) { return str_replace(" ","---",$bozza_testo); } } // seconda ConcreteClass class TemplateSoloOggetto extends TemplateBase { function correggiOggetto($bozza_oggetto) { return str_replace(" ","~",$bozza_oggetto); } } class MessaggioCompleto { private $bozza_testo; private $bozza_oggetto; function __construct($bozza_oggetto_per_scrittura, $bozza_testo_per_scrittura) { $this->oggetto = $bozza_testo_per_scrittura; $this->testo = $bozza_oggetto_per_scrittura; } function estraiTesto() {return $this->oggetto;} function estraiOggetto() {return $this->testo;} function estraiTestoAndtesto() { return $this->estraiOggetto() . " .:::. " . $this->estraiTesto(); } } scrivi_messaggio("Esempio pratico di utilizzo del Template Method Pattern."); $messaggio_completo = new MessaggioCompleto("Ciao HTML.it","Salutoni da Mountain View."); $template_con_testo = new TemplateConTesto(); $template_solo_oggetto = new TemplateSoloOggetto(); scrivi_messaggio("Prima esecuzione: mostra sia oggetto che testo:"); scrivi_messaggio($template_con_testo->visualizzaMessaggioCompleto($messaggio_completo)); scrivi_messaggio("Seconda esecuzione: mostra il solo oggetto:"); scrivi_messaggio($template_solo_oggetto->visualizzaMessaggioCompleto($messaggio_completo)); scrivi_messaggio("Esecuzioni terminate."); function scrivi_messaggio($output) { echo $output."<br/>rn"; } ?>
L’esecuzione del sorgente proposto dovrebbe generare un output come il seguente:
Esempio pratico di utilizzo del Template Method Pattern. Prima esecuzione: mostra sia oggetto che testo: Ciao---HTML.it .:::. Salutoni---da---Mountain---View. Seconda esecuzione: mostra il solo oggetto: Ciao~HTML.it Esecuzioni terminate
Riassumendo, nell'applicazione viene introdotto un metodo template che non farà altro che definire la struttura dell’algoritmo per il quale è stata concepita la superclasse, sono poi presenti un’operazione primitiva denominata correggiOggetto()
destinata all’overriding per definire una nuova implementazione su tale membro nella classe secondaria e un hook (“correggiTesto()
”), cioè un’operazione che potrà eventualmente essere utilizzata ai fini della ridefinizione, ma, essendo opzionale, non influirà sull'algoritmo se inutilizzata. Classicamente gli hooks nei Template Method Pattern sono dei metodi vuoti che vengono chiamati nella classe principale e non svolgono alcuna operazione in quanto privi di elementi, possono però essere implementati nelle sottoclassi.
È consigliabile utilizzare questa particolare tipologia di Design Pattern con estrema moderazione, questo perché esso invita lo sviluppatore a caricare le classi secondarie di metodi implementati, a ciò si potrà comunque ovviare progettando con attenzione la classe base.
Conclusioni
In questa breve trattazione è stato preso in analisi il Design Pattern Template Method che consiste nella definizione di una classe astratta contenente un metodo (il template) e nell'utilizzo di sottoclassi destinate ad effettuarne l’implementazione tramite il meccanismo dell’ereditarietà.
Sono state quindi esposte le caratteristiche di tale schema progettuale e sottolineata la sua utilità nella riduzione delle duplicazioni di porzioni di sorgente, infine, ne sono stati descritti i meccanismi e la struttura per poi proporre un esempio pratico del suo funzionamento.