Template Method Pattern
- Type : Comportemental
- Difficulté : 4/10
- Définition succincte : Le Template Method Pattern est un design pattern comportemental qui permet de définir la structure d'un algorithme dans une méthode, tout en déléguant certaines étapes spécifiques aux sous-classes. Cela permet de centraliser la logique générale tout en laissant les sous-classes définir les détails de l'implémentation pour certaines étapes spécifiques.
- Contexte spécifique à Laravel : En Laravel, ce pattern est utilisé dans les Blade Templates, où les vues parent définissent une structure globale et les vues enfants remplissent ou modifient certaines parties spécifiques grâce aux sections et à l'héritage des layouts.
Objectif du Template Method Pattern
L'objectif principal du Template Method Pattern est de centraliser la logique commune tout en permettant aux sous-classes d'implémenter des variations spécifiques. Cela est particulièrement utile lorsque plusieurs classes ont un comportement similaire, mais qu'elles diffèrent sur certaines étapes spécifiques.
Structure du Template Method Pattern
- Template Method : Méthode définissant la structure générale de l'algorithme, avec certaines étapes déléguées aux sous-classes.
- AbstractClass : Classe abstraite qui implémente le Template Method et définit certaines étapes, en laissant d'autres à être définies par les sous-classes.
- ConcreteClass : Classe concrète qui implémente les étapes spécifiques de l'algorithme.
1. Exemple d'utilisation dans Laravel
Laravel utilise le Template Method Pattern dans le système de Blade Templates, où une vue parent peut définir un layout global, et des vues enfants remplissent ou modifient certaines sections spécifiques.
<!-- resources/views/layouts/app.blade.php -->
<!DOCTYPE html>
<html>
<head>
<title>@yield('title')</title>
</head>
<body>
<header>
<h1>Welcome to My App</h1>
</header>
<main>
@yield('content')
</main>
<footer>
<p>© 2024 My App</p>
</footer>
</body>
</html>
Ensuite, la vue enfant remplit les sections :
<!-- resources/views/pages/home.blade.php -->
@extends('layouts.app')
@section('title', 'Home Page')
@section('content')
<p>This is the home page content.</p>
@endsection
Cela démontre comment la structure générale est définie dans la vue parent, tandis que les sections spécifiques sont définies dans les vues enfants.
2. Implémentation complète dans Laravel
Prenons un exemple d'une application Laravel où tu veux générer différents types de rapports (comme des rapports en PDF, CSV, ou JSON). Bien que la structure générale de la génération de rapports soit la même (préparation des données, formatage, exportation), le format des données (PDF, CSV, JSON) diffère. Le Template Method Pattern permet de gérer cette situation en définissant un flux général pour la génération du rapport et en laissant les sous-classes gérer les spécificités de formatage.
a) Créer une classe de base abstraite ReportGenerator
Cette classe va définir la structure de la génération du rapport avec des étapes communes, comme la préparation des données, et laisser les sous-classes définir la manière dont les données seront formatées.
// app/Services/Reports/ReportGenerator.php
namespace App\Services\Reports;
abstract class ReportGenerator
{
// Méthode template qui définit la structure générale de la génération du rapport
public function generateReport($data)
{
// 1. Préparer les données
$preparedData = $this->prepareData($data);
// 2. Formatage spécifique du rapport (implémenté par les sous-classes)
$formattedData = $this->formatReport($preparedData);
// 3. Exporter le rapport (implémenté par les sous-classes)
$this->exportReport($formattedData);
}
// Étape commune à toutes les sous-classes : préparation des données
protected function prepareData($data)
{
// Exemple simple : trier les données
return collect($data)->sort();
}
// Étapes spécifiques que les sous-classes doivent implémenter
abstract protected function formatReport($data);
abstract protected function exportReport($formattedData);
}
b) Implémenter les sous-classes spécifiques
Chaque sous-classe va implémenter les méthodes formatReport() et exportReport() pour définir comment les données sont formatées et exportées dans des formats spécifiques (PDF, CSV, JSON, etc.).
1. Générateur de rapport CSV
Cette sous-classe formate les données en CSV et les exporte dans un fichier CSV.
// app/Services/Reports/CsvReportGenerator.php
namespace App\Services\Reports;
class CsvReportGenerator extends ReportGenerator
{
protected function formatReport($data)
{
// Formatage des données en CSV
return implode(',', $data->toArray());
}
protected function exportReport($formattedData)
{
// Exporter le rapport CSV (par exemple, sauvegarder dans un fichier)
file_put_contents(storage_path('reports/report.csv'), $formattedData);
}
}
2. Générateur de rapport JSON
Cette sous-classe formate les données en JSON et les exporte dans un fichier JSON.
// app/Services/Reports/JsonReportGenerator.php
namespace App\Services\Reports;
class JsonReportGenerator extends ReportGenerator
{
protected function formatReport($data)
{
// Formatage des données en JSON
return json_encode($data->toArray());
}
protected function exportReport($formattedData)
{
// Exporter le rapport JSON (par exemple, sauvegarder dans un fichier)
file_put_contents(storage_path('reports/report.json'), $formattedData);
}
}
3. Générateur de rapport PDF
Cette sous-classe utilise une bibliothèque PDF pour formater et exporter les données dans un fichier PDF.
// app/Services/Reports/PdfReportGenerator.php
namespace App\Services\Reports;
use PDF; // Supposons qu'on utilise une bibliothèque PDF
class PdfReportGenerator extends ReportGenerator
{
protected function formatReport($data)
{
// Formatage des données pour un rapport PDF (en HTML par exemple)
return view('reports.pdf', ['data' => $data])->render();
}
protected function exportReport($formattedData)
{
// Exporter le rapport PDF (sauvegarder un fichier PDF)
$pdf = PDF::loadHTML($formattedData);
$pdf->save(storage_path('reports/report.pdf'));
}
}
c) Utiliser le Template Method Pattern dans une commande CLI
Nous allons maintenant créer une commande CLI pour permettre la génération de différents types de rapports.
// app/Console/Commands/GenerateReport.php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Services\Reports\CsvReportGenerator;
use App\Services\Reports\JsonReportGenerator;
use App\Services\Reports\PdfReportGenerator;
class GenerateReport extends Command
{
protected $signature = 'report:generate {type}';
protected $description = 'Generate a specific report in CSV, JSON or PDF format';
public function handle()
{
$type = $this->argument('type');
$data = [3, 1, 2]; // Exemple de données à traiter
$reportGenerator = $this->getReportGenerator($type);
if ($reportGenerator) {
$reportGenerator->generateReport($data);
$this->info("Report generated successfully in {$type} format!");
} else {
$this->error('Invalid report type. Please choose between csv, json, or pdf.');
}
}
protected function getReportGenerator($type)
{
return match ($type) {
'csv' => new CsvReportGenerator(),
'json' => new JsonReportGenerator(),
'pdf' => new PdfReportGenerator(),
default => null,
};
}
}
d) Exécution de la commande
Tu peux exécuter la commande suivante pour générer des rapports dans différents formats :
php artisan report:generate csv
php artisan report:generate json
php artisan report:generate pdf
Exemple de sortie
Lorsque tu exécutes php artisan report:generate csv, le fichier report.csv est généré avec les données en format CSV. De même pour les commandes JSON et PDF, les fichiers report.json et report.pdf seront générés dans le répertoire de stockage.
Avantages du Template Method Pattern
- Réutilisation de code : La structure générale de l'algorithme est définie une seule fois dans la classe de base, ce qui permet de réutiliser la logique commune sans la dupliquer.
- Flexibilité : Les sous-classes peuvent personnaliser certaines étapes spécifiques de l'algorithme tout en respectant la structure générale imposée par la méthode template.
- Clarté : Le pattern rend le flux de l'algorithme plus clair, en définissant quelles étapes sont fixes et lesquelles peuvent être modifiées.
- Facilité de maintenance : Il est plus facile de maintenir ou de modifier la logique commune dans une seule classe de base, sans avoir à modifier chaque sous-classe.
Inconvénients
- Complexité potentielle : Si l'algorithme devient trop complexe, ou si trop d'étapes doivent être personnalisées dans les sous-classes, le pattern peut ajouter de la complexité inutile.
- Rigidité de la structure : Si la structure générale de l'algorithme change souvent, ce pattern peut être contraignant, car toutes les sous-classes doivent suivre la même structure.
Conclusion
Le Template Method Pattern est une solution élégante pour définir la structure générale d'un algorithme tout en permettant aux sous-classes de personnaliser certaines étapes spécifiques comme les détails propres à chaque cas. Ce pattern est très utilisé dans Laravel via les Blade Templates, mais il peut aussi être appliqué à d'autres scénarios comme la génération de rapports ou la gestion de workflows complexes.