Décorateur (patron de conception) — Wikipédia

En informatique, plus précisément en génie logiciel, un décorateur est le nom d'une des structures de patron de conception.

Un décorateur permet d'attacher dynamiquement de nouvelles responsabilités à un objet. Les décorateurs offrent une alternative assez souple à l'héritage pour composer de nouvelles fonctionnalités.

Le pattern Décorateur est l'un des vingt-trois patterns GOF. Il résout les problématiques suivantes :

  • L'ajout (et la suppression) des responsabilités à un objet dynamiquement au moment de l'exécution.
  • Il constitue une alternative aux sous-classes pour une surcharge flexible des fonctionnalités.

Quand on utilise l'héritage, les différentes sous-classes étendent une classe mère en différentes manières. Mais une extension est attachée à la classe au moment de la compilation, et ne peut pas changer à l'exécution.

Exemple en Java

[modifier | modifier le code]
// ______________________________________________________________________ // Déclarations public interface IVehicule { 	public String getNom(); 	public String getMarque(); 	public int getPrix(); 	public int getPoids(); }  public abstract class Voiture implements IVehicule { 	private String aNom; 	private String aMarque;  	protected void setNom(String pNom) { 		this.aNom = pNom; 	}  	public String getNom() { 		return this.aNom; 	}  	protected void setMarque(String pMarque) { 		this.aMarque = pMarque; 	}  	public String getMarque() { 		return this.aMarque; 	} }  public class DS extends Voiture { 	public DS() { 		this.setNom("DS"); 		this.setMarque("Citroën"); 	}  	public int getPrix() { 		return 30000; 	}  	public int getPoids() { 		return 1500; 	} }  // ______________________________________________________________________ // Décorateurs public abstract class VoitureAvecOption extends Voiture { 	private IVehicule aVehicule;  	protected void setVehicule(IVehicule pVehicule) { 		this.aVehicule = pVehicule; 	}  	public IVehicule getVehicule() { 		return this.aVehicule; 	} }  class VoitureAvecToitOuvrant extends VoitureAvecOption { 	public int getPrix() { 		return this.getVehicule().getPrix() + 10000; 	}  	public int getPoids() { 		return this.getVehicule().getPoids() + 15; 	} }  //On garde le nom du pattern Decorator pour savoir qu'on wrap un objet  class DSAvecToitOuvrantDecorator extends VoitureAvecToitOuvrant { 	public DSAvecToitOuvrantDecorator(DS pDS) { 		this.setVehicule(pDS); 	} }  public class Main { 	// ______________________________________________________________________ 	// Implémentation 	public static void main(String[] args) { 		DS vDS = new DS(); 		IVehicule vDSOption = new DSAvecToitOuvrantDecorator(vDS); 		System.out.println(vDSOption.getPoids() + " - " + vDSOption.getPrix()); 	} } 

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 VoitureAvecClimatisation : Option {     public VoitureAvecClimatisation (Voiture originale) : base(originale, 1.0) { } } class VoitureAvecParachute : Option {     public VoitureAvecParachute (Voiture originale) : base(originale, 10.0) { } } class VoitureAmphibie : Option {     public VoitureAmphibie (Voiture originale) : base(originale, 100.0) { } }  //______________________________________________________________________ // Implémentation  class Program {     static void Main() {         Voiture astonMartin= new AstonMartin();         astonMartin = new VoitureAvecClimatisation(astonMartin);         astonMartin = new VoitureAvecParachute(astonMartin);         astonMartin = new VoitureAmphibie(astonMartin);          Console.WriteLine(astonMartin.Prix); // affiche 1110.99     } } 

Exemple en C++

[modifier | modifier le code]
# include <iostream> # include <memory>  class IVoiture { public:   virtual double prix() = 0; };  class Aston_martin : public IVoiture { public:   double prix() override { return 999.99l; } };  class Option_voiture : public IVoiture { public:   Option_voiture(std::unique_ptr<IVoiture> voiture, double prix_option)     : voiture_(std::move(voiture))     , prix_option_(prix_option)   {}   double prix() override { return voiture_->prix() + prix_option_; } protected:   std::unique_ptr<IVoiture> voiture_;   double prix_option_; };  class Option_clim : public Option_voiture { public:   Option_clim(std::unique_ptr<IVoiture> voiture) : Option_voiture(std::move(voiture), 1.0) {} };  class Option_parachute : public Option_voiture { public:   Option_parachute(std::unique_ptr<IVoiture> voiture) : Option_voiture(std::move(voiture), 10.0) {} };  class Option_amphibie : public Option_voiture { public:   Option_amphibie(std::unique_ptr<IVoiture> voiture) : Option_voiture(std::move(voiture), 100.0) {} };  int main() {   auto voiture = std::unique_ptr<IVoiture>(std::make_unique<Aston_martin>());   voiture = std::make_unique<Option_clim>(std::move(voiture));   voiture = std::make_unique<Option_parachute>(std::move(voiture));   voiture = std::make_unique<Option_amphibie>(std::move(voiture));   std::cout << voiture->prix() << "\n"; // affiche 1110.99   return 0; } 
<?php  // Interface pour rendre un objet affichable interface Affichable { 	public function affiche(); }  // Classe contenant un message affichable class Message implements Affichable {  	protected $message = ''; 	 	public function __construct($message) { 		$this->message = $message; 	} 	 	public function affiche() { 		echo $this->message; 	}  }  // Une classe abstraite de décoration de message affichable abstract class DecorateurDeMessage implements Affichable { 	 	protected $messageDecore = null;   	public function __construct(Affichable $messageDecore) { 		$this->messageDecore = $messageDecore; 	} }  // Une classe pour "décorer" un message en gras class MessageEnGras extends DecorateurDeMessage {  	public function affiche() { 		echo '<strong>'; 		$this->messageDecore->affiche(); 		echo '</strong>'; 	} }   // Une classe pour "décorer" un message en italique class MessageEnItalique extends DecorateurDeMessage {  	public function affiche() { 		echo '<em>'; 		$this->messageDecore->affiche(); 		echo '</em>'; 	} }  // Création du message $message = new Message('le message');  // On met le message en gras et en italique $messageDecore = new MessageEnItalique( new MessageEnGras( $message ) ); // On affiche le message décoré $messageDecore->affiche(); ?> 

En effet, les langages Delphi et Free Pascal supportent les class helpers qui rendent inutile le patron de conception décorateur.

Attention car Embarcadero déconseille l'utilisation des class helpers[1].

program NoMoreDecorators;  type   TMyObject = class     procedure WriteHello;   end;    TMyObjectHelper = class helper for TMyObject     procedure WriteHello(const Name: string); overload;   end;  procedure TMyObject.WriteHello; begin   writeln('Hello'); end;  procedure TMyObjectHelper.WriteHello(const Name: string); begin   writeln('Hello, ', Name, '!'); end;  var   o: TMyObject; begin   o := TMyObject.Create;   o.WriteHello;   o.WriteHello('Jean');   o.Free; end. 

source : Delphi GOF DesignPatterns (CodePlex)

Notes et références

[modifier | modifier le code]
  1. (en) « Class and Record Helpers (Delphi) », sur embarcadero.com (consulté le ).

Sur les autres projets Wikimedia :

Articles connexes

[modifier | modifier le code]