Modèles de conception avancés en C++ : de la théorie au code réel
Les modèles de conception sont des solutions éprouvées pour des problèmes typiques en programmation orientée objet. Si vous maîtrisez déjà les modèles de base (Singleton, Factory, Observer), il est temps de passer au niveau supérieur. Dans cet article, nous analyserons quatre modèles avancés : Visitor, Strategy, State et Command. Tous les exemples sont écrits en C++17/20 moderne avec des pointeurs intelligents, du polymorphisme et des templates.
1. Modèle Visitor (Visiteur)
Le modèle Visitor permet d'ajouter de nouvelles opérations à une hiérarchie de classes sans modifier les classes elles-mêmes. C'est une solution idéale pour travailler avec des arbres AST, des scènes graphiques ou des systèmes d'exportation.
Problème
Vous avez une hiérarchie de formes géométriques (Circle, Rectangle, Triangle). Vous devez implémenter des opérations : calcul de surface, rendu, sérialisation en JSON. Si vous ajoutez des méthodes à chaque classe, le principe d'ouverture/fermeture est violé.
Solution en C++17
#include <iostream>#include <memory>#include <vector>
// Forward declarationclass Circle;class Rectangle;
class Visitor {public: virtual void visit(Circle& c) = 0; virtual void visit(Rectangle& r) = 0; virtual ~Visitor() = default;};
class Shape {public: virtual void accept(Visitor& v) = 0; virtual ~Shape() = default;};
class Circle : public Shape {public: double radius = 5.0; void accept(Visitor& v) override { v.visit(*this); }};
class Rectangle : public Shape {public: double width = 4.0, height = 6.0; void accept(Visitor& v) override { v.visit(*this); }};
// Visiteur concretclass AreaVisitor : public Visitor {public: void visit(Circle& c) override { std::cout << "Circle area: " << 3.14159 * c.radius * c.radius << ""; } void visit(Rectangle& r) override { std::cout << "Rectangle area: " << r.width * r.height << ""; }};
int main() { std::vector<std::unique_ptr<Shape>> shapes; shapes.push_back(std::make_unique<Circle>()); shapes.push_back(std::make_unique<Rectangle>());
AreaVisitor av; for (auto& s : shapes) { s->accept(av); } return 0;}2. Modèle Strategy (Stratégie)
Strategy permet de changer l'algorithme de traitement des données pendant l'exécution. Contrairement à Visitor qui travaille avec une hiérarchie d'objets, Strategy encapsule un algorithme individuel.
Scénario réel
Système de compression de fichiers. L'utilisateur choisit l'algorithme : ZIP, GZIP ou un algorithme personnalisé. Au lieu d'une chaîne de if-else, nous utilisons Strategy.
Implémentation avec std::function
#include <iostream>#include <functional>#include <string>
class CompressionContext {private: std::function<void(const std::string&)> strategy_;public: explicit CompressionContext(std::function<void(const std::string&)> strategy) : strategy_(std::move(strategy)) {}
void setStrategy(std::function<void(const std::string&)> strategy) { strategy_ = std::move(strategy); }
void compress(const std::string& data) { if (strategy_) { strategy_(data); } else { std::cout << "No strategy set"; } }};
int main() { auto zip = [](const std::string& d) { std::cout << "Compressing with ZIP: " << d << ""; }; auto gzip = [](const std::string& d) { std::cout << "Compressing with GZIP: " << d << ""; };
CompressionContext ctx(zip); ctx.compress("Hello World"); // ZIP
ctx.setStrategy(gzip)