Guide des Design Patterns en Développement Logiciel

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();
?>

Étiquettes: PHP design-patterns Software-Architecture Singleton factory-pattern

Publié le 4 août à 14h39