VI. Le composite▲
Définition : Le composite est un pattern qui permet de manipuler un ensemble d'objets comme un seul.
VI-A. 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 :
VI-B. 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 :
#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
#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-C. 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.