Classification des Design Patterns
- Création : Singleton, Factory, Abstract Factory, Builder.
- Structure : Adapter, Decorator, Facade.
- Comportement : Strategy, Observer, Chain of Responsibility.
- Architecture : Registry.
1. Le Singleton (Pattern d'Unicité)
Ce pattern garantit qu'une classe ne possède qu'une seule instance accessible globalement. Il est idéal pour gérer des ressources partagées comme les connexions aux bases de données.
<?php
class GestionnaireBaseDonnees {
private static $_instanceUnique = null;
private $pdo;
private function __construct() {
$dsn = "mysql:host=localhost;dbname=prod_db;charset=utf8";
$this->pdo = new PDO($dsn, "admin", "password_secure");
}
private function __clone() {}
private function __wakeup() {}
public static function obtenirInstance(): self {
if (is_null(self::$_instanceUnique)) {
self::$_instanceUnique = new self();
}
return self::$_instanceUnique;
}
public function executerRequete($sql, $params = []) {
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
}
// Utilisation
$db = GestionnaireBaseDonnees::obtenirInstance();
$utilisateurs = $db->executerRequete("SELECT * FROM users WHERE actif = ?", [1]);
?>
2. Le Factory (La Fabrique)
La fabrique permet d'instancier des objets sans exposer la logique complexe de création au client, en s'appuyant sur une interface commune.
<?php
interface MethodePaiement {
public function traiter(float $montant);
}
class PaiementStripe implements MethodePaiement {
public function traiter($montant) {
return "Traitement de {$montant}€ via Stripe.";
}
}
class PaiementPaypal implements MethodePaiement {
public function traiter($montant) {
return "Traitement de {$montant}€ via PayPal.";
}
}
class FabriquePaiement {
public static function creer($type): MethodePaiement {
return match($type) {
'stripe' => new PaiementStripe(),
'paypal' => new PaiementPaypal(),
default => throw new Exception("Mode de paiement non supporté."),
};
}
}
// Utilisation
$paiement = FabriquePaiement::creer('stripe');
echo $paiement->traiter(150.00);
?>
3. L'Abstract Factory (Fabrique Abstraite)
Ce patttern fournit une interface pour créer des familles d'objets liés ou dépendants sans spécifier leurs classes concrètes.
<?php
interface ComposantUI {
public function rendu();
}
interface FabriqueInterface {
public function creerBouton(): ComposantUI;
public function creerMenu(): ComposantUI;
}
class ThemeSombreBouton implements ComposantUI {
public function rendu() { return "Bouton Noir"; }
}
class ThemeClairBouton implements ComposantUI {
public function rendu() { return "Bouton Blanc"; }
}
class FabriqueThemeSombre implements FabriqueInterface {
public function creerBouton(): ComposantUI { return new ThemeSombreBouton(); }
public function creerMenu(): ComposantUI { /* ... */ }
}
// Utilisation
function genererInterface(FabriqueInterface $fabrique) {
$btn = $fabrique->creerBouton();
echo $btn->rendu();
}
genererInterface(new FabriqueThemeSombre());
?>
4. Le Strategy (Stratégie)
Permet de définir une famille d'algorithmes, de les encapsuler et de les rendre interchangeables dynamiquement selon le contexte.
<?php
interface CalculFraisLivraison {
public function calculer($poids): float;
}
class LivraisonRapide implements CalculFraisLivraison {
public function calculer($poids): float { return $poids * 5.5; }
}
class LivraisonStandard implements CalculFraisLivraison {
public function calculer($poids): float { return $poids * 2.0; }
}
class Commande {
private $strategie;
public function __construct(CalculFraisLivraison $s) {
$this->strategie = $s;
}
public function obtenirTotal($poids) {
return $this->strategie->calculer($poids);
}
}
// Utilisation
$commande = new Commande(new LivraisonRapide());
echo $commande->obtenirTotal(10); // Frais express
?>
5. L'Observer (Observateur)
Définit une dépendance de type un-à-plusieurs : lorsqu'un objet change d'état, tous ses dépendants sont informés et mis à jour automatiquement.
<?php
interface Observateur {
public function notifier($message);
}
class ServiceEmail implements Observateur {
public function notifier($message) {
echo "Email envoyé : " . $message;
}
}
class GestionnaireStock {
private $observateurs = [];
public function ajouterAlerte(Observateur $obs) {
$this->observateurs[] = $obs;
}
public function miseAJourStock($quantite) {
if ($quantite < 5) {
foreach ($this->observateurs as $obs) {
$obs->notifier("Stock critique : $quantite restants.");
}
}
}
}
// Utilisation
$gestion = new GestionnaireStock();
$gestion->ajouterAlerte(new ServiceEmail());
$gestion->miseAJourStock(3);
?>
6. Chain of Responsibility (Chaîne de Responsabilité)
Évite le couplage entre l'émetteur d'une requête et son récepteur en donnant à plus d'un objet la chance de traiter la requête.
<?php
abstract class Validateur {
protected $suivant;
public function definirSuivant(Validateur $v) {
$this->suivant = $v;
return $v;
}
abstract public function verifier($donnees);
}
class ValidateurEmail extends Validateur {
public function verifier($donnees) {
if (!filter_var($donnees['email'], FILTER_VALIDATE_EMAIL)) {
return "Email invalide.";
}
return $this->suivant ? $this->suivant->verifier($donnees) : true;
}
}
class ValidateurMdp extends Validateur {
public function verifier($donnees) {
if (strlen($donnees['password']) < 8) {
return "Mot de passe trop court.";
}
return $this->suivant ? $this->suivant->verifier($donnees) : true;
}
}
// Utilisation
$chaine = new ValidateurEmail();
$chaine->definirSuivant(new ValidateurMdp());
$resultat = $chaine->verifier(['email' => 'test@dev.fr', 'password' => '123']);
?>
7. L'Adapter (Adaptateur)
Convertit l'interface d'une classe en une autre interface attendue par le client, permettant à des classes incompatibles de collaborer.
<?php
// Système tiers avec des noms de méthodes différents
class ServiceLegacy {
public function recupererInfosAnciennes() {
return "Données formatées à l'ancienne";
}
}
interface NouvelleInterface {
public function getData(): string;
}
class AdaptateurService implements NouvelleInterface {
private $legacy;
public function __construct(ServiceLegacy $s) {
$this->legacy = $s;
}
public function getData(): string {
return $this->legacy->recupererInfosAnciennes();
}
}
// Utilisation
$service = new AdaptateurService(new ServiceLegacy());
echo $service->getData();
?>
8. Le Builder (Monteur)
Sépare la construction d'un objet complexe de sa représentation, permettant à la même procédure de construction de créer différentes représentations.
<?php
class RequeteSQLBuilder {
private $requete = [];
public function selectionner($colonnes) {
$this->requete['select'] = $colonnes;
return $this;
}
public function depuis($table) {
$this->requete['from'] = $table;
return $this;
}
public function ou($condition) {
$this->requete['where'][] = $condition;
return $this;
}
public function generer(): string {
$sql = "SELECT " . $this->requete['select'] . " FROM " . $this->requete['from'];
if (!empty($this->requete['where'])) {
$sql .= " WHERE " . implode(" AND ", $this->requete['where']);
}
return $sql;
}
}
// Utilisation
$sql = (new RequeteSQLBuilder())
->selectionner('nom, email')
->depuis('utilisateurs')
->ou('age > 18')
->generer();
?>