Patrons de conception/Décorateur
Un décorateur est le nom d'un patron de conception de structure.
Patron de conception | |
---|---|
Catégorie : « Gang of Four » – Structure | |
Nom français : | Décorateur |
Nom anglais : | Decorator |
Attribuer dynamiquement de nouveaux comportements ou responsabilités à un objet |
Un décorateur permet d'attacher dynamiquement de nouveaux comportements ou responsabilités à un objet. Les décorateurs offrent une alternative assez souple à l'héritage pour composer de nouvelles fonctionnalités.
Objectifs
modifierBeaucoup de langages de programmation orientés objets ne permettent pas de créer dynamiquement des classes, et la conception ne permet pas de prévoir quelles combinaisons de fonctionnalités sont utilisées pour créer autant de classes.
Exemple : Supposons qu'une classe de fenêtre Window ne gère pas les barres de défilement. On créé une sous-classe ScrollingWindow. Maintenant, il faut également ajouter une bordure. Le nombre de classes croît rapidement si on utilise l'héritage : on créé les classes WindowWithBorder et ScrollingWindowWithBorder.
Par contre, les classes décoratrices sont allouées dynamiquement à l'utilisation, permettant toutes sortes de combinaisons. Par exemple, les classes d'entrées-sorties de Java permettent différentes combinaisons (FileInputStream + ZipInputStream, ...).
En reprenant l'exemple des fenêtres, on créé les classes ScrollingWindowDecorator et BorderedWindowDecorator sous-classes de Window stockant une référence à la fenêtre à « décorer ». Étant donné que ces classes décoratives dérivent de Window, une instance de ScrollingWindowDecorator peut agir sur une instance de Window ou une instance de BorderedWindowDecorator.
Exemples
modifierCe programme illustre l'exemple des fenêtres ci-dessus.
// interface des fenêtres
interface Window
{
public void draw(); // dessine la fenêtre
public String getDescription(); // retourne une description de la fenêtre
}
// implémentation d'une fenêtre simple, sans barre de défilement
class SimpleWindow implements Window
{
public void draw()
{
// dessiner la fenêtre
}
public String getDescription()
{
return "fenêtre simple";
}
}
Les classes suivantes contiennent les décorateurs pour toutes les classes de fenêtres, y compris les décorateurs eux-mêmes.
// classe décorative abstraite, implémente Window
abstract class WindowDecorator implements Window
{
protected Window decoratedWindow; // la fenêtre décorée
public WindowDecorator (Window decoratedWindow)
{
this.decoratedWindow = decoratedWindow;
}
}
// décorateur concret ajoutant une barre verticale de défilement
class VerticalScrollBarDecorator extends WindowDecorator
{
public VerticalScrollBarDecorator (Window decoratedWindow)
{
super(decoratedWindow);
}
public void draw()
{
drawVerticalScrollBar();
decoratedWindow.draw();
}
private void drawVerticalScrollBar()
{
// afficher la barre verticale de défilement
}
public String getDescription()
{
return decoratedWindow.getDescription() + ", avec une barre verticale de défilement";
}
}
// décorateur concret ajoutant une barre horizontale de défilement
class HorizontalScrollBarDecorator extends WindowDecorator
{
public HorizontalScrollBarDecorator (Window decoratedWindow)
{
super(decoratedWindow);
}
public void draw()
{
drawHorizontalScrollBar();
decoratedWindow.draw();
}
private void drawHorizontalScrollBar()
{
// afficher la barre horizontale de défilement
}
public String getDescription()
{
return decoratedWindow.getDescription() + ", avec une barre horizontale de défilement";
}
}
Voici un programme de test qui créé une fenêtre pleinement décorée (barres de défilement verticale et horizontale) et affiche sa description :
public class DecoratedWindowTest
{
public static void main(String[] args)
{
Window decoratedWindow =
new HorizontalScrollBarDecorator (
new VerticalScrollBarDecorator(
new SimpleWindow()
)
);
// afficher la description
System.out.println(decoratedWindow.getDescription());
}
}
Ce programme affiche :
fenêtre simple, avec une barre verticale de défilement, avec une barre horizontale de défilement
Les deux décorateurs utilisent la description de la fenêtre décorée et ajoute un suffixe.
Ici l'héritage est utilisé.
//______________________________________________________________________
// Déclarations
abstract class Voiture
{
public abstract double Prix { get; }
}
class AstonMartin : Voiture
{
public override double Prix { get { return 999.99; } }
}
//______________________________________________________________________
// Décorateurs
class Option : Voiture
{
protected Voiture _originale;
protected double _tarifOption;
public Option(Voiture originale, double tarif)
{
_originale = originale;
_tarifOption = tarif;
}
public override double Prix
{
get { return _originale.Prix + _tarifOption; }
}
}
class Climatisation : Option
{
public Climatisation (Voiture originale) : base(originale, 1.0) { }
}
class Parachute : Option
{
public Parachute (Voiture originale) : base(originale, 10.0) { }
}
class Amphibie : Option
{
public Amphibie (Voiture originale) : base(originale, 100.0) { }
}
//______________________________________________________________________
// Implémentation
class Program
{
static void Main()
{
Voiture astonMartin= new AstonMartin();
astonMartin = new Climatisation(astonMartin);
astonMartin = new Parachute(astonMartin);
astonMartin = new Amphibie(astonMartin);
Console.WriteLine(astonMartin.Prix); // affiche 1110.99
}
}
Patrons connexes
modifierRéférences externes
modifier- Le patron "décorateur" sur le site developpez.com
- (anglais) Description par Vince Huston
- (anglais) Decorator Pattern
- (anglais) C# Conception par James W. Cooper
- (anglais) Approche PHP et redécorée
- (anglais) Approche Delphi
- (anglais) Article Trois approches java pour "décorer" votre code" par Michael Feldman
- (anglais) Article "Utiliser le patron "décorateur"" par Budi Kurniawan