Introduction : pourquoi les patrons de conception en C++
Les patrons de conception (design patterns) sont des solutions éprouvées aux problèmes typiques rencontrés lors du développement de logiciels. En C++, avec son puissant système de types, RAII et l'héritage multiple, les patrons acquièrent une flexibilité particulière. Ils aident à rendre le code plus lisible, maintenable et évolutif.
Dans cet article, nous examinerons 4 patrons clés du catalogue GoF (Gang of Four) : Singleton, Factory Method, Observer et Strategy. Chaque patron sera illustré par un exemple de code réel en C++17/20.
Patrons 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'approche moderne utilise une variable statique locale (thread-safe depuis C++11).
Exemple : Journaliseur d'application
class Logger {public: // Suppression de la copie et de l'affectation Logger(const Logger&) = delete; Logger& operator=(const Logger&) = delete;
static Logger& getInstance() { static Logger instance; // thread-safe depuis C++11 return instance; }
void log(const std::string& message) { std::lock_guard<std::mutex> lock(m_mutex); std::cout << "[LOG] " << message << std::endl; }
private: Logger() = default; // constructeur privé ~Logger() = default; std::mutex m_mutex;};
// Utilisationint main() { Logger::getInstance().log("Application démarrée"); Logger::getInstance().log("Erreur : fichier non trouvé"); return 0;}Avantages : garantie d'unicité, initialisation paresseuse, sécurité des threads.
Inconvénients : complique les tests (état global), viole le principe de responsabilité unique.
Patrons de création : Factory Method
Factory Method définit une interface pour créer un objet, mais permet aux sous-classes de décider quelle classe instancier. En C++, il est souvent implémenté via des fonctions virtuelles et des pointeurs intelligents.
Exemple : Génération de différents types de documents
// Produit abstraitclass Document {public: virtual void open() = 0; virtual void save() = 0; virtual ~Document() = default;};
// Produits concretsclass PDFDocument : public Document {public: void open() override { std::cout << "PDF ouvert"; } void save() override { std::cout << "PDF sauvegardé"; }};
class WordDocument : public Document {public: void open() override { std::cout << "Word ouvert"; } void save() override { std::cout << "Word sauvegardé"; }};
// Créateur (Creator)class Application {public: virtual std::unique_ptr<Document> createDocument() = 0; virtual ~Application() = default;
void newDocument() { auto doc = createDocument(); doc->open(); // travail avec le document }};
// Créateurs concretsclass PDFApplication : public Application {public: std::unique_ptr<Document> createDocument() override { return std::make_unique<PDFDocument>(); }};
class WordApplication : public Application {public: std::unique_ptr<Document> createDocument() override { return std::make_unique<WordDocument>(); }};
// Utilisationint main() { std::unique_ptr<Application> app = std::make_unique<PDFApplication>(); app->newDocument(); // Sortie : "PDF ouvert" return 0;}Ce patron est idéal lorsque les types exacts des objets à créer ne sont pas connus à l'avance.
Patrons comportementaux : Observer
Blogs
Book Recommendations
Lire aussi
WebSocket en Go : création d'applications temps réel de niveau avancé
10 meilleurs frameworks Go pour le développement web : de A à Z
Modèles de conception en Kotlin avec exemples de code
Files d'attente de tâches en JavaScript (Node.js) : guide complet
Salaires des développeurs Swift en Russie : aperçu du marché 2025