« Patrons de conception/Objet composite » : différence entre les versions

Contenu supprimé Contenu ajouté
m 73 versions depuis w:Objet composite : Patrons de conception/Objet composite
+
Ligne 1 :
<noinclude>{{Patrons de conception}}
{{ébauche|informatique}}
{{Patron de conception|Objet composite|Composite|Créer une classe de manipulation de composants en utilisant la même interface commune que les composants}}</noinclude>
En [[génie logiciel]], un '''objet composite''' est un [[patron de conception]] (''design pattern'') [[patron de conception#Structure|structurel]].
 
Dans ce [[../|patron de conception]], un '''objet composite''' est constitué d'un ou de plusieurs objets similaires (ayant des fonctionnalités similaires).
==Motivation==
En [[programmation objet]], un objet composite est constitué d'un ou de plusieurs objets similaires (ayant des fonctionnalités similaires). L'idée est de manipuler un groupe d'objets de la même façon que s'il s'agissait d'un seul objet. Les objets ainsi regroupés doivent posséder des opérations communes, c'est-à-dire un "dénominateur commun".
Les objets ainsi regroupés doivent posséder des opérations communes, c'est-à-dire un "dénominateur commun".
 
==Quand l'utiliser==
Vous avez l'impression d'utiliser de multiples objets de la même façon, souvent avec des lignes de code identiques ou presque.
Par exemple, lorsque la seule et unique différence entre deux méthodes est que l'une manipule un objet de type <tt>Carré</tt>, et l'autre un objet <tt>Cercle</tt>.
Lorsque, pour le traitement considéré, la différenciation n'a ''pas besoin'' d'exister, il serait plus simple de considérer l'ensemble de ces objets comme homogène.
 
== Diagramme de classes UML ==
==Structures==
Le patron de conception Objet composite peut être représenté par le diagramme de classes UML suivant :
[[Image:UML DP ObjetComposite.png|center|frame|Diagramme des classes UML du patron de conception Objet composite]]
 
* '''ComponentObjet''' ''(composant)''
** déclare l'interface pour la composition d'objetobjets
** met en œuvre le comportement par défaut
** déclare une [[interface]] pour l'accès aux composants enfants
 
* '''LeafObjetSimple''' ''(feuille)''
** représente desles objets feuillemanipulés, dansayant laune compositioninterface commune
 
* '''CompositeObjetComposite'''
** définit un comportement pour les composants ayant des enfants
** stocke les composants enfants
** met en œuvre la gestion des composants enfants de l'interface <tt>Component</tt>
 
La classe utilisatrice manipule les objets de la composition à travers l'interface <tt>Objet</tt>.
* '''Client'''
** manipule les objets de la composition à travers l'interface <tt>Composite</tt>
 
== Exemples ==
[[Image:Composite UML class diagram fr.svg|center|480px|La classe composant dérive "composite" et "feuille". Un composite a 0 composants ou plus.]]
 
==Exemple= [[Programmation C++|C++]] ===
<source lang="cpp">
// Cet exemple representereprésente la hiérarchie d'un système de fichiers : fichiers/répertoires
 
class Composant
{
// L'objet abstrait qui sera 'composé' dans le composite
// Dans notre exemple, il s'agira d'un fichier ou d'un répertoire
 
public:
// Parcours récursif de l'arbre
// (Utilisez plutôt le Design Pattern "Visiteur" à la place de cette fonction)
virtual void listerNoms() = 0 ;
 
protected:
class Composant {
std::string name;
//L'objet abstrait qui sera 'composé' dans le composite
//Dans notre exemple, il s'agira d'un fichier ou d'un répertoire
public:
//Parcours récursif de l'arbre
//(Utilisez plutôt le Design Pattern "Visiteur" à la place de cette fonction)
virtual void ls_r() = 0 ;
protected:
std::string name;
};
 
class File : public Composant
{ //Leaf
public:
void listerNoms()
void ls_r() { std::cout << name << std::endl; }
{
std::cout << name << std::endl;
}
};
 
class Repertoire : public Composant
{ //Composite
//Le repertoirerépertoire est aussi un 'composant' car il peut être sous-répertoire
protected:
std::list<Composant*> files; //List Liste des composants enfants
 
public:
void ls_r() { public:
void listerNoms()
std::cout << "[" << name << "]" << std::endl;
{
for( std::list<Composant*>::iterator it = files.begin();
it !=std::cout files.end();<< it"[" ++<< )name {<< "]" << std::endl;
for( std::list<Composant*>::iterator it = files.begin();
it->ls_r();
it != files.end(); it ++ )
}
} {
it->listerNoms();
}
}
};
</source>
 
==Exemple= [[Programmation Java|Java]] ===
L'exemple qui suit, écrit en [[Java (langage)|Java]], met en œuvre une classe graphique qui peut être ou bien une ellipse ou une composition de différents graphiques.
Chaque graphique peut être imprimé.
 
Il pourrait être étendu en y ajoutant d'autres formes (rectangle etc.) et méthodes (translation etc.).
 
<source lang=java>
import java.util.ArrayList;
 
interface Graphic
{
 
//Imprime le graphique.
public void print();
 
}
 
class CompositeGraphic implements Graphic
{
 
//Collection de graphiques enfants.
private ArrayList<Graphic> mChildGraphics = new ArrayList<Graphic>();
 
//Imprime le graphique.
public void print() {
{
for (Graphic graphic : mChildGraphics) {
{
graphic.print();
}
Ligne 93 ⟶ 107 :
 
//Ajoute le graphique à la composition composition.
public void add(Graphic graphic) {
{
mChildGraphics.add(graphic);
}
 
//Retire le graphique de la composition.
public void remove(Graphic graphic) {
{
mChildGraphics.remove(graphic);
}
Ligne 104 ⟶ 120 :
}
 
class Ellipse implements Graphic
{
 
//Imprime le graphique.
public void print() {
{
System.out.println("Ellipse");
}
Ligne 113 ⟶ 130 :
}
 
public class Program
{
public static void main(String[] args)
 
{
public static void main(String[] args) {
//Initialise quatre ellipses
Ellipse ellipse1 = new Ellipse();
Ligne 143 ⟶ 161 :
</source>
 
==Exemple= en[[Programmation PHP|PHP 5]] ===
<source lang=php>
<?php
class Component
{
// Attributs
 
private $basePath;
// Attributes
private $basePathname;
private $nameparent;
private $parent;
public function __construct($name, CDirectory $parent = null)
{
// Debug : echo "constructor Component";
$this->name = $name;
$this->parent = $parent;
if($this->parent != null)
{
// Debug : echo "constructor Component";
$this->parent->addChild($this);
$this->basePathname = $this->parent->getPath()name;
$this->parent = $parent;
if($this->parent != null)
{
$this->parent->addChild($this);
$this->basePath = $this->parent->getPath();
}
else
{
$this->basePath = '';
}
}
else
{
$this->basePath = '';
}
}
 
// Getters
public function getBasePath() { return $this->basePath; }
public function getName() { return $this->name; }
public function getParent() { return $this->parent; }
 
// Getters Setters
public function getBasePathsetBasePath($basePath) { return $this->basePath = $basePath; }
public function getNamesetName($name) { return $this->name = $name; }
public function getParentsetParent(CDirectory $parent) { return $this->parent = $parent; }
 
// SettersMéthode
public function setBasePathgetPath($basePath) { return $this->basePath = getBasePath().'/'.$basePaththis->getName(); }
public function setName($name) { $this->name = $name; }
public function setParent(CDirectory $parent) { $this->parent = $parent; }
// Method
public function getPath() { return $this->getBasePath().'/'.$this->getName(); }
}
 
class CFile extends Component
{
// Attributs
private $type;
// Attributes
private $type;
 
public function __construct($name, $type, CDirectory $parent = null)
{
public function __construct($name, $type, CDirectory $parent = null)
// Debug : echo "constructor CFile";
{
// Debug : echo "constructor$this->type CFile"= $type;
$this->type = $type;
 
// Retrieve constructor of Component
parent::__construct($name, $parent);
}
// Getters
public function getType() { return $this->type; }
 
// SettersGetters
public function setTypegetType($type) { return $this->type = $type; }
 
// Setters
// Methods of Component class
public function getNamesetType($type) { return parent::getName().'.'.$this->getType()type = $type; }
 
public function getPath() { return parent::getPath().'.'.$this->getType(); }
// Méthodes de la classe Component
public function getName() { return parent::getName().'.'.$this->getType(); }
public function getPath() { return parent::getPath().'.'.$this->getType(); }
}
 
Ligne 215 ⟶ 229 :
{
 
// AttributesAttributs
private $childs;
public function __construct($name, CDirectory $parent = null)
{
// Debug : echo "constructor CDirectory";
$this->childs = array();
 
// Retrieve constructor of Component
parent::__construct($name, $parent);
}
 
// Getters
public function getChilds() { return $this->childs; }
 
// Setters
public function setChilds($childs) { $this->childs = $childs; }
 
// Méthodes
public function addChild(Component $child)
{
$child->setParent($this);
$this->childs[] = $child;
}
 
public function showChildsTree($level = 0)
// Methods
public function addChild(Component $child)
{
$child->setParent($this);
$this->childs[] = $child;
}
public function showChildsTree($level = 0)
{
echo "<br/>".str_repeat('&nbsp;', $level).$this->getName();
foreach($this->getChilds() as $child)
{
echo "<br/>".str_repeat('&nbsp;', $level).$this->getName();
if($child instanceof self)
foreach($this->getChilds() as $child)
{
{
$child->showChildsTree($level+1);
if($child instanceof self)
}
else {
$child->showChildsTree($level+1);
{
}
echo "<br/>".str_repeat('&nbsp;', $level+1).$child->getName();
} else
{
echo "<br/>".str_repeat('&nbsp;', $level+1).$child->getName();
}
}
}
}
}
?>
</source>
Exemple d'utilisation (''example of use''):
<source lang=php>
<?php
Ligne 273 ⟶ 286 :
?>
</source>
résultat à l'écran (''result on the screen'') :
 
Résultat à l'écran :
root
dir1
Ligne 283 ⟶ 296 :
dir3
 
=== [[Programmation C sharp|C#]] ===
==Exemple C#==
 
Produisant un résultat similaire à l'exemple en phpPHP, une variante en C#.
 
Dans ce code la méthode Draw() correspond à la méthode opération() du diagramme de classes.
 
<source lang=csharp>
abstract class Composant
/// <summary> Par simplicité, ni méthode Add ni Remove ni GetChild. </summary>
{
abstract class Composant {
public int Level = 0;
public string Nom;
public virtual void Draw() {
{
for (var i = 0; i < Level; i++)
Console.Write(" ");
Ligne 300 ⟶ 314 :
}
 
class Feuille : Composant
{
public override void Draw() {
{
base.Draw();
Console.WriteLine("Feuille : {0}", Nom);
Ligne 307 ⟶ 323 :
}
 
// Par simplicité, ni méthode Add ni Remove ni GetChild.
class Composite : Composant {
class Composite : Composant
{
public Composant[] Composants; // serait private s'il y avait une méthode Add.
public override void Draw() {
{
base.Draw();
Console.WriteLine("Composite : {0}", Nom);
foreach (Composant composant in Composants) {
{
composant.Level = this.Level + 1;
composant.Draw();
Ligne 319 ⟶ 339 :
}
 
class Program
{
static void Main(string[] args) {
{
 
//__________________________________________________________________________
// On crée en général la structure par de multiples appels à la méthode Add.
 
var cadre= new Composite() {
Nom = "fond d 'écran",
Composants = new Composant[] {
new Composite() {
Nom = "ciel",
Composants = new Composant[] {
new Feuille() { Nom="soleil" }}},
new Composite() {
Nom = "mer",
Composants = new Composant[] {
new Composite() {
Nom="bateau",
Composants = new Composant[] {
new Feuille() { Nom="kevin" },
Ligne 351 ⟶ 372 :
</source>
 
Et le résultat :
Composite : fond d'écran
 
Composite : ciel
<source lang=vb>
Feuille : soleil
Composite : fond d écran
Composite : cielmer
Feuille Composite : soleilbateau
Composite Feuille : merkevin
Composite Feuille : bateaukatsumi
Feuille : kevin
Feuille : katsumi
</source>
 
[[Catégorie:Patron de conception]]
 
[[Catégorie:Patrons de conception (livre)]]
[[bg:Композиция (шаблон)]]
[[de:Kompositum (Entwurfsmuster)]]
[[en:Composite pattern]]
[[es:Composite (patrón de diseño)]]
[[it:Composite]]
[[ja:Composite パターン]]
[[ko:Composite 패턴]]
[[pl:Kompozyt (wzorzec projektowy)]]
[[pt:Composite]]
[[ru:Компоновщик (шаблон проектирования)]]
[[th:คอมโพสิตแพตเทิร์น]]
[[vi:Composite pattern]]