Il framework chiama te, non il contrario
L'inversione di controllo e il principio fondante di ogni framework: non sei tu a chiamare il framework, e il framework che chiama te. Il Template Method e la realizzazione piu diretta di questo principio — una classe base definisce lo scheletro di un algoritmo, lasciando alle sottoclassi il compito di riempire i passi concreti. Il framework sa quando chiamare, la sottoclasse sa cosa fare. Questa divisione di responsabilita e cio che distingue un framework da una libreria.
In Soft PHP MVC, la classe astratta Command definisce il lifecycle di un comando CLI: inizializzazione, parsing dell'input, esecuzione di handle(Input $input, Output $output): int, gestione del codice di ritorno. Il comando concreto — MigrateFreshCommand, KeyGenerateCommand, CacheClearCommand — implementa solo handle(). Il resto e ereditato, garantito, testato. Il developer non deve preoccuparsi di come l'input viene parsato o come l'output viene formattato — il template glielo fornisce.
Cos'e il Template Method: definizione formale
Il Gang of Four definisce il Template Method come un pattern comportamentale che "definisce lo scheletro di un algoritmo in un metodo, rinviando alcuni passi alle sottoclassi. Il Template Method permette alle sottoclassi di ridefinire certi passi di un algoritmo senza cambiarne la struttura". I due concetti chiave sono: i metodi template (che definiscono lo scheletro e non devono essere sovrascritti) e i metodi hook (che le sottoclassi implementano o sovrascrivono).
A differenza dello Strategy, che usa la composizione (il comportamento e un oggetto separato), il Template Method usa l'ereditarieta (il comportamento e definito nella sottoclasse). Questa differenza ha conseguenze pratiche: lo Strategy permette di cambiare comportamento a runtime, il Template Method lo fissa a compile-time. Ma il Template Method e piu semplice da usare — basta estendere una classe e implementare i metodi astratti. Non serve creare interfacce, implementazioni separate e meccanismi di iniezione.
Il lifecycle dei modelli come template
Il modello base del framework definisce un lifecycle preciso: beforeSave(), scrittura su database, afterSave(). Le sottoclassi possono sovrascrivere i metodi hook per aggiungere comportamento — validazione, pulizia dati, invalidazione cache — senza toccare la logica di persistenza. E il Template Method applicato alla persistenza: il "come si salva" e fisso, il "cosa succede prima e dopo" e personalizzabile.
L'attributo #[\Override] di PHP 8.4 aggiunge sicurezza a questo pattern: se una sottoclasse sovrascrive beforeSave() e la classe base rinomina il metodo, il compilatore segnala l'errore. Senza #[\Override], il metodo sovrascritto diventerebbe un metodo orfano — chiamato da nessuno, silenziosamente ignorato. E la classe di bug piu insidiosa: il codice "funziona" ma non fa quello che credi. L'attributo trasforma un errore silenzioso in un errore esplicito — esattamente il tipo di feedback che un framework deve dare.
Hook concreti nel modello base
Il modello base di Soft PHP MVC offre diversi punti di estensione:
- beforeSave() — validazione, normalizzazione dati, slug generation
- afterSave() — invalidazione cache, aggiornamento indici, notifiche
- beforeDelete() — controllo dipendenze, soft delete check
- afterDelete() — pulizia file associati, cascading manuale
- booting() — registrazione trait, configurazione iniziale del modello
Ogni hook ha un valore di ritorno opzionale: beforeSave() puo restituire false per annullare il salvataggio. Questo meccanismo di veto e un'estensione del pattern classico che aggiunge potere espressivo senza complicare l'interfaccia.
Il sistema CLI come Template Method
La classe Command del framework e un altro esempio canonico. Il template definisce: registrazione del comando nel kernel, parsing dei flag e degli argomenti, chiamata di handle(), gestione del codice di uscita. Il developer che crea un nuovo comando deve implementare solo handle() e dichiarare $signature — il framework gestisce tutto il resto.
Questo approccio riduce drasticamente il boilerplate: ogni comando CLI ha esattamente lo stesso comportamento per input/output, error handling e formatting. La coerenza non dipende dalla disciplina del developer ma dalla struttura del template. Un nuovo developer puo creare un comando CLI perfettamente integrato senza conoscere i dettagli del kernel — deve solo riempire il metodo handle() con la logica specifica.
Hook vs composizione: il dilemma dell'ereditarieta
Il Template Method si basa sull'ereditarieta — e l'ereditarieta e un'arma a doppio taglio. Il GoF stesso avvertiva: "favorisci la composizione sull'ereditarieta". Ma ci sono casi dove l'ereditarieta e la scelta giusta: quando il rapporto e genuinamente "e un" (un MigrateFreshCommand e un Command), e quando lo scheletro e stabile e non cambiera spesso.
Nel framework, il Template Method convive con la composizione: i Command usano l'ereditarieta per il lifecycle, ma compongono servizi per la logica. MigrateFreshCommand eredita da Command ma usa MigrationRunner come collaboratore. L'ereditarieta definisce il quando, la composizione definisce il come. Due pattern che si completano invece di competere — e questa combinazione e la chiave per un'architettura equilibrata.
Quando preferire Strategy al Template Method
La scelta tra Template Method e Strategy dipende dalla natura della variazione:
- Template Method — la variazione e nel "cosa" (passi diversi dello stesso algoritmo), la struttura e stabile
- Strategy — la variazione e nel "come" (algoritmi alternativi), il comportamento puo cambiare a runtime
- Template Method — le varianti sono poche e note a priori
- Strategy — le varianti possono crescere e non sono note a priori
In Soft PHP MVC, la grammar SQL usa lo Strategy (le varianti crescono con i database supportati), mentre il lifecycle dei comandi usa il Template Method (la struttura e stabile e le varianti sono prevedibili). Ogni pattern nel posto giusto.
La fiducia nel contratto
Il Template Method e un atto di fiducia bidirezionale. Il framework si fida che la sottoclasse implementera handle() correttamente. La sottoclasse si fida che il framework chiamara handle() nel momento giusto, con l'input gia parsato e l'output gia configurato. Questa fiducia reciproca e cio che rende possibile un framework: un contratto tra chi definisce la struttura e chi la riempie di significato.
Hollywood Principle — "don't call us, we'll call you" — e il nome informale dell'inversione di controllo. E anche una metafora della maturita architetturale: un framework giovane espone utility che il codice applicativo chiama; un framework maturo definisce punti di estensione che il codice applicativo implementa. Il Template Method e il punto di estensione piu semplice possibile — e spesso e tutto cio che serve per costruire un'architettura solida e manutenibile.