Accueil
Rechercher:
sur developpez.com sur les forums
Forums | Tutoriels | F.A.Q's | Participez | Hébergement | Contacts
Club Emploi Blogs   TV   Dév. Web PHP XML Python Autres 2D-3D-Jeux Sécurité Windows Linux PC Mac
Accueil Conception Java DotNET Visual Basic  C  C++ Delphi MS-Office SQL & SGBD Oracle  4D  Business Intelligence
FORUMS JAVA FAQs TUTORIELS JAVASEARCH SOURCES LIVRES OUTILS, EDI & API ECLIPSE NETBEANS BLOG DISCUSSIONS TV
Trucs et astuces
Validité des paramètres
Documenter votre code
Assertions
Tests unitaires
Design patterns - GOF
Adaptateur
Composite
Décorateur
etat
Façade
Kit
Monteur
Pont
Proxy
Singleton
Design patterns - Avalon
IOC - Inversion Of Control
SOC - Seperation Of Concerns
COP - Component Orientated Programming
SOP - Service Orientated Programming
Autres articles
Cahier
XML Sax en java
Fractal
AspectJ

Voir aussi
Patterns du GRASP
héritage avec des EJB Entiy CMP

Ressouces java
Informations
Cours
Livres
FAQ
Outils
EDI
Ressources uml
Cours
Livres
Forums d'entraide
Géneral Java
J2EE
JBuilder
Outils EDI
Méthodes/UML/Mérise


Le décorateur
18 Avril 2003
Version 1.0
Par Sébastien MERIC
Remerciements : Stefan Bertholon

Synonyme

Emballage

Synopsis

Ajout dynamique de responsabilités à un objet. L'ajout de responsabilités à un objet sonne évidemment comme un héritage. C'est en effet, le moyen le plus évident de lui fournir des responsabilités supplémentaires. Le manque de souplesse de cette méthode (l'héritage) est bien entendu, son inconvénient majeur. Premièrement, l'héritage n'est pas toujours possible. Deuxièmement, l'héritage peut donner lieu à la prolifération de classes. Enfin, les responsabilités supplémentaires ne sont pas dynamiques.

Exploration

L'héritage n'est pas toujours possible
Vous n'avez en effet pas toujours moyen d'accéder à la classe mère, vous ne l'avez pas nécessairement développée vous-même et elle peut être définie comme étant finale. Il peut aussi arriver que la classe ne soit pas finale mais qu'en hériter vous rende nerveux à l'idée de devoir maintenir dans toutes vos classes héritières toute modification apportée par l'éditeur de cette classe. Bref que vous ne puissiez réellement pas ou que vous ne désiriez pas, ne change rien à votre problème : il faut éviter d'hériter
Evite la prolifération de classes :
Imaginons que l'on ai définie une classe dont on veut étendre les capacités. Par exemple nous avons la classe Logger et on veut ajouter à chaque message envoyer vers le logger, l'heure et la date d'émission. Imaginons de plus que nous voulions aussi définir une classe pour un affichage console, un log dans un fichier, un log par email à un administrateur un affichage SWING ! Dans chaque cas, il faut pouvoir afficher ou non l'heure et la date. Nous voilà donc obligés de surcharger la classe logger (pour un fichier) 3 fois pour les divers types de logger et 2 fois pour que chacun affiche l'heure et la date, ou non.

schema sans décorateur

Les responsabilités supplémentaires ne sont pas dynamiques
Et le dynamisme peut se représenter par plusieurs choses aussi utiles qu'esthétiques (si tant est que le développement vous paraisse esthétique). Plusieurs points donc :
  • Le dynamisme de déploiement : c'est donc un fichier de configuration qui vous permet de choisir le mode d'utilisation de vos classes.
  • Un dynamisme en runtime : à tout moment vous pouvez basculer du mode horodaté au mode sans horodatage, du mode swing au mode console, etc.
  • Enfin, et on découvre alors là une grande puissance du pattern Décorateur, vous pouvez composer les différentes parties entre elles. Un exemple : Logger classique (donc fichier) associé à LoggerHorodaté (donc horodatage des messages) associés à LoggerSwing (donc affichage écran graphique) donne des résultats dans un fichier et dans un écran, le tout horodaté. Pour faire cela avec l'héritage pur, il m'aurait fallu hériter par exemple de LoggerSwingHorodaté et ajouter les responsabilités pourtant déjà implémentées de log dans un fichier ! Soit encore une classe.
  • Enfin, dynamisme de votre application car l'ajout d'une nouvelle extenssion devient simple, il suffit d'ajouter une classe tandis que dans la présentation précédente, vous ajoutez une classe multipliée par le nombre de combinaisons requises.

schema du logger avec décorateur

Structure

Sur le schéma précédent, nous pouvons étudier la structure requise pour mettre en place le décorateur. Il nous faut une interface racine qui présente l'ensemble des responsabilités de notre panel d'outils. Une classe d'implémentation par défaut évidemment, c'est quand même généralement le cas et ceci permet en plus d'utiliser une fabrique qui renvoie cette classe par défaut si rien ne lui est précisé, ou que la configuration provoque une erreur.

Ensuite il nous faut aussi une racine pour tous les décorateurs qui maintiennent une poignée sur un autre décorateur afin de déléguer une partie de son travail bien entendu.

Le reste du pattern, contient les classes qui implémentent cette "racine" afin d'étendre les responsabilités.

diagramme

Implémentation

Source

/*
 * Logger.java
 *
 * Created on 10 mars 2003, 19:11
 */

package com.developpez.decorateur;

/**
 *
 * @author  smeric
 */
public interface Logger {

    /**
     * Log le message.
     */
    void log(java.lang.String msg);

}

Source

/*
 * DefaultLogger.java
 *
 * Created on 10 mars 2003, 19:15
 */

package com.developpez.decorateur;

import java.io.*;

/**
 * Classe d'implémentation du logger par défaut.
 * Cette classe loggue les messages sans fioriture dans un flux qui peut
 * être soit un fichier soit la sortie standard.
 * @author  smeric pour developpez.com
 */
public class DefaultLogger implements Logger {

    /** 
     * Créer une nouvelle instance de DefaultLogger.<p>
     * Cette instance a besoin de connaitre un flux pour écrire à l'intérieur.
     */
    public DefaultLogger(PrintStream printSream) {
        setPrintStream(writter);
    }

    /**
     * Log le message.
     */
    public void log(java.lang.String msg) {
        getPrintStream().println(msg);
    }

    private void setPrintStream(PrintStream value) {
        printStream = value;
    }

    private Writter getPrintStream() {
        if (null == printStream) {
            return System.out;
        }
        return printStream;
    }

    private PrintStream printStream;

}

Source

/*
 * LoggerDecorateur.java
 *
 * Created on 10 mars 2003, 19:32
 */

package com.developpez.decorateur;

/**
 *
 * @author  smeric
 */
public class LoggerDecorateur implements Logger {

    /**
     * Pas de constructeur par défaut, il faudra appeler celui-ci.
     * Ce constructeur prend en paramètre un autre logger pour enrichir ces possibilités
     * et refuse (voir le mutateur) un logger null.
     */
    public LoggerDecorateur(Logger logger) {
        setLogger(logger);
    }

    /**
     * Log le message.
     */
    public void log(String msg) {
        getLogger().log(msg);
    }

    private void setLogger(Logger value) {
        assert null != value : "Impossible de décorer un logger null";
        logger = value;
    }

    private Logger logger;
}

Remarque concernant la structure

Si vous vous trouvez face à la problématique exprimée en premier point, la classe mère n'est pas accessible pour l'héritage, il faudra implémenter la classe par défaut sous la forme d'un adaptateur

Copyright (c) 2003 Sébastien MERIC. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with no Invariant Sections, with the Front-Cover Texts being Le décorateur, and Back-Cover Texts being Ce document à été écrit pour la communauté de développeurs francophones "www.developpez.com". A copy of the license is included in the section entitled "GNU Free Documentation License".
/java/uml/decorateur  

Responsables bénévoles de la rubrique Java : Christophe Jollivet et Eric Siber - Contacter par EMail :
Vos questions techniques : forum d'entraide Java - Publiez vos articles, tutoriels et cours
et rejoignez-nous dans l'équipe de rédaction du club d'entraide des développeurs francophones
Nous contacter - Copyright © 2000-2008 www.developpez.com - Legal informations.