Présentation des principaux design patterns en C++


précédentsommairesuivant

VI. Le composite

Définition : Le composite est un pattern qui permet de manipuler un ensemble d'objets comme un seul.

VI-1. Quand a-t-on besoin de celui-ci ?

Hors du code, le pattern composite est l'un des patterns que l'on croise le plus souvent sans s'en rendre compte puisque dès que l'on navigue dans l'arborescence d'un disque dur, nous le côtoyons. En effet, quand nous naviguons, nous pouvons manipuler un dossier comme bon nous semble, quoi que contienne ce dossier (autres dossiers, fichiers...). Et c'est précisément ce que propose le composite : pouvoir s'abstraire du nombre d'objets réels et de les manipuler comme s'il n'y en avait qu'un.

De ce fait le composite va tout d'abord fournir une interface pour permettre de manipuler les objets, puis deux classes qui héritent de cette interface. Une qui représente un objet 'terminal' et une autre pour représenter l'objet composite en lui même.

De ce fait, le diagramme UML du pattern est :

Diagramme UML du DP composite
Diagramme UML du pattern composite

VI-2. Première implémentation

En reprenant l'exemple de l'arborescence d'un disque dur sous un système unix, un premier code peut être :

 
Sélectionnez

#ifndef COMPOSITE_H
#define COMPOSITE_H

#include <string>
#include <vector>

//un fichier de base
class FichierAbstrait
{
        static const int m_taille;

        protected:
        std::string m_nom;

        public:
        virtual int GetTaille() const;
        virtual void Afficher() const ;

        virtual ~FichierAbstrait() =0;
        FichierAbstrait(const std::string& nom);
};

//un fichier terminal
class Fichier :public FichierAbstrait 
{
        private:
        std::string m_type;

        public:
        void Afficher() const ;
        Fichier(const std::string& nom,const std::string& type);
        ~Fichier();
};

//un conteneur
class Dossier : public FichierAbstrait
{
        private:
        std::vector<FichierAbstrait*> m_listfichier;

        public:

        void Afficher() const;
        int GetTaille() const;

        Dossier& Add(Dossier* file);

        void Add(Fichier* file);

        Dossier(const std::string& path);
        ~Dossier();

};

#endif

Et dans le fichier composite.cpp

 
Sélectionnez

#include <iostream>
#include <string>
#include <iterator>

#include "composite.h"

using namespace std;

const int FichierAbstrait::m_taille=1;
//=======
FichierAbstrait::FichierAbstrait(const std::string& nom):
m_nom(nom)
{

}

int FichierAbstrait::GetTaille() const 
{
    return m_taille;
}

void FichierAbstrait::Afficher() const 
{
cout<<m_nom<<" "<<GetTaille();
}

FichierAbstrait::~FichierAbstrait() 
{

}
//=======
Fichier::Fichier(const string& nom,const string& type):
FichierAbstrait(nom),m_type(type)
{

}
void Fichier::Afficher() const 
{
    FichierAbstrait::Afficher();cout<<" "<<m_type<<endl;
}

Fichier::~Fichier()
{

}
//=======
Dossier::Dossier(const string& path):FichierAbstrait(path)
{

}

void Dossier::Afficher() const 
{
        //pour chaque élément du vecteur, on l'affiche
        vector<FichierAbstrait*>::const_iterator itb=m_listfichier.begin();
        const vector<FichierAbstrait*>::const_iterator ite=m_listfichier.end();

        cout<<"["<<m_nom<<"]";
        for(;itb!=ite;itb++)
        {
            (*itb)->Afficher();
        };
}

int Dossier::GetTaille() const
{
        //on fait la somme de la taille de chaque élément 
        int somtaille=0;
        
        vector<FichierAbstrait*>::const_iterator itb=m_listfichier.begin();
        const vector<FichierAbstrait*>::const_iterator ite=m_listfichier.end();

        for(;itb!=ite;itb++)
        {
        somtaille+=(*itb)->GetTaille();        
        }
        
        return somtaille;
}

Dossier::~Dossier()
{
        //on détruit chaque élément
        vector<FichierAbstrait*>::const_iterator itb=m_listfichier.begin();
        const vector<FichierAbstrait*>::const_iterator ite=m_listfichier.end();

        for(;itb!=ite;itb++)
        {
            delete (*itb) 
        };
}

Dossier& Dossier::Add(Dossier* file)
{
        m_listfichier.push_back(file);
        return (*file);        
}

void Dossier::Add(Fichier* file)
{
                m_listfichier.push_back(file);
}
//=======
int main(void)
{
        Dossier root("/");
        root.Add(new Dossier("home/")).Add(new Dossier("david/")).Add(new Fichier("composite.h","text"));

        root.Afficher();

}        

Comme dans le décorateur, rien de bien dur dans l'implémentation à proprement parler. La seule chose notable est dans la classe de l'objet composite (ici dossier) : la redéfinition des fonctions virtuelles est souvent une boucle qui appelle les fonctions de chaque membre du vecteur.

VI-3. Pas de templates

Comme pour le décorateur, le composite est plus une notion qu'un service clé en main. De ce fait, je pense qu'on peut difficilement fournir une version template du composite.


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2007 Côme David. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.