Introduction aux patrons de conception en C++
Les patrons de conception (design patterns) sont des solutions architecturales éprouvées pour les problèmes de développement typiques. Dans le monde du C++, ils sont particulièrement importants car ils permettent de créer un code flexible, extensible et maintenable. Dans cet article, nous allons analyser quatre patrons fondamentaux : Singleton, Factory Method, Observer et Strategy — avec des exemples complets en C++ moderne (C++17/20).
Chaque patron sera accompagné d'un exemple pratique, d'un diagramme de classes et d'explications sur son utilisation. Le matériel est destiné aux développeurs déjà familiers avec les bases du C++ et de la POO.
1. Patron de création Singleton
Singleton garantit qu'une classe n'a qu'une seule instance et fournit un point d'accès global à celle-ci. En C++, l'implémentation classique utilise une méthode statique et un constructeur privé.
Quand l'utiliser
- Gestion de la connexion à la base de données
- Système de journalisation
- Gestionnaire de cache
- Configuration de l'application
Exemple d'implémentation (Singleton thread-safe)
#include <iostream>#include <mutex>#include <memory>
class Logger {private: static std::unique_ptr<Logger> instance; static std::mutex mtx; Logger() { std::cout << "Logger créé" << std::endl; } public: Logger(const Logger&) = delete; Logger& operator=(const Logger&) = delete; static Logger* getInstance() { std::lock_guard<std::mutex> lock(mtx); if (!instance) { instance.reset(new Logger()); } return instance.get(); } void log(const std::string& msg) { std::cout << "[LOG] " << msg << std::endl; }};
std::unique_ptr<Logger> Logger::instance = nullptr;std::mutex Logger::mtx;
int main() { Logger* log1 = Logger::getInstance(); Logger* log2 = Logger::getInstance(); log1->log("Message de test"); // log1 et log2 pointent vers le même objet std::cout << "log1 == log2: " << (log1 == log2) << std::endl; return 0;}Approche C++ moderne (Singleton de Meyers)
class ConfigManager {public: static ConfigManager& getInstance() { static ConfigManager instance; // thread-safe en C++11+ return instance; } void setParam(const std::string& key, const std::string& value) { params[key] = value; } std::string getParam(const std::string& key) { return params[key]; } private: ConfigManager() = default; std::map<std::string, std::string> params;};2. Patron de création Factory Method
Factory Method définit une interface pour créer un objet, mais permet aux sous-classes de choisir la classe concrète de l'objet à créer. Ce patron est particulièrement utile lorsque le type de l'objet n'est pas connu à l'avance.
Structure du patron
- Product — classe abstraite du produit
- ConcreteProduct — implémentation concrète du produit
- Creator — classe abstraite du créateur avec la méthode de fabrique
- ConcreteCreator — redéfinit la méthode de fabrique
Exemple : système de notifications
#include <iostream>#include <memory>#include <string>
// Produit abstraitclass Notification {public: virtual void send(const std::string& message) = 0; virtual ~Notification() = default;};
// Produits concretsclass EmailNotification : public Notification {public: void send(const std::str