IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Java Discussion :

Conception : héritage et instanceof


Sujet :

Langage Java

  1. #1
    Membre Expert Avatar de herve91
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    1 282
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 1 282
    Par défaut Conception : héritage et instanceof
    Bonsoir,
    Supposons une classe mère abstraite Element disposant d'un certain nombre d'attributs, et dont dérivent les classes concrètes ElementA, ElementB, ElementC, chacune possédant ses attributs propres.
    On souhaite représenter dans un JPanel PanelElement les caractéristiques d'un objet sous-type d'Element.
    Quelle serait la façon la plus élégante et la plus "orientée objet" de définir la classe PanelElement, et éventuellement ses sous-types ?
    Par exemple (toute autre suggestion est la bienvenue...) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    abstract class PanelElement extends JPanel {
      public PanelElement(Element element) {
        this.element = element;
        add(new JLabel("Date début"));
        add(new JLabel(String.valueOf(element.getDateDebut())));
        ...
      }
    }
     
    class PanelElementA extends PanelElement {
      public PanelElementA(ElementA elementA) {
        super(elementA);
        this.elementA = elementA;
        add(new JLabel("Heure début");
        add(new JLabel(String.valueOf(elementA.getHeureDebut())));
        ...
      }
    }
    Je précise que Element et ses sous-classes sont de simples business objects (beans) et qu'il n'est pas possible d'enrichir ses classes pour fournir d'autres méthodes que les getter/setter sur les attributs.
    Le problème est le suivant : je dispose d'une collection d'objets de type ElementA, ElementB, ...
    Comment instancier le panel correspondant en évitant des appels à instanceof ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    if (element instanceof ElementA) {
      return new PanelElementA((ElementA) element);
    } else if (element instanceof ElementB) {
      ...
    }
    Si on est amené à créer un nouveau type ElementD, il faut prévoir son panel correspondant PanelElementD. Il est pénible d'avoir à rechercher dans le code les occurrences de instanceof ElementX pour compléter avec le nouveau type partout où c'est nécessaire...
    D'où la question : y a-t-il un design pattern ou des techniques OO permettant de s'affranchir tout ou partie de faire de la reconnaissance de type à l'exécution ?

  2. #2
    Membre averti
    Inscrit en
    Avril 2002
    Messages
    36
    Détails du profil
    Informations forums :
    Inscription : Avril 2002
    Messages : 36
    Par défaut
    Je ne suis pas encore vraiment au top sur les design pattern, mais le cas qui te pose problème me semble pas mal adapté à se documenter sur les factory et les décorateurs ^^.

    Le concept qu'il te faudrait mettre en place est de déléguer à une classe tierce la responsabilité d'instancier le Panel adapté en fonction de l'objet courant.
    L'intérêt qui se présentera assez vite c'est que dans le cas de l'ajout d'un nouveau sous-type impliquera "uniquement" la création du nouveau bean et l'introduction de la prise en charge dans la côté Factory et la création de l'objet de vue correspondant.

  3. #3
    Membre expérimenté
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    319
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2006
    Messages : 319
    Par défaut
    Effectivement, le motif Factory serait utile ici.

    Autrement pour éviter les tests avec instanceof tu pourrais utiliser un tableau associatif liant des classes d'Element aux classes de Panel correspondants.

    Exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class Herve91Factory
    {
        private Map<Class, Class> panelsByElement;
     
        public Herve91Facrtory()
        {
            panelsByElement = new HashMap<Class, Class>();
            panelsByElement.put(ElementA.class, PanelElementA.class);
            panelsByElement.put(ElementB.class, PanelElementB.class);
            ...
        }
     
        public PanelElement createPanel(Element element)
        {
            PanelElement panel = panelsByElement.get(element.getClass()).newInstance();
            ...
        }
     
        ...
     
    }

  4. #4
    Membre Expert Avatar de herve91
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    1 282
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 1 282
    Par défaut
    Merci pour vos réponses, effectivement j'ai pensé à faire un tableau associatif, mais la solution que tu proposes TigRoO° ne fonctionne pas. En effet, si tu as bien regardé les constructeurs des classes PanelElementX, elles prennent en entrée un objet de type ElementX, donc il n'y a pas de constructeur par défaut.

    Voici ce à quoi j'ai pensé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    public class Herve91Factory {
        interface PanelFactory {
          PanelElement newInstance(Element element);
        }
    
        static class PanelAFactory implements PanelFactory {
           public PanelElement newInstance(Element element) {
              return new PanelElementA((ElementA) element);
           }
        }
        ...
    
        private Map<Class, PanelElementFactory> panelsByElement;
    
        public Herve91Factory()
        {
            panelsByElement = new HashMap<Class, PanelElementFactory>();
            panelsByElement.put(ElementA.class, new PanelAFactory());
            panelsByElement.put(ElementB.class, new PanelBFactory());
            ...
        }
     
        public PanelElement createPanel(Element element)
        {
            PanelElement panel = ((PanelElementFactory) panelsByElement.get(element.getClass())).newInstance(element);
            ...
        }
    }
    On a évité les tests avec instanceof, mais il y a toujours une conversion de type... bonne nouvelle quand même, elle est "encapsulée"...
    Si qq voit une solution encore plus générique

  5. #5
    Expert confirmé
    Avatar de sinok
    Profil pro
    Inscrit en
    Août 2004
    Messages
    8 765
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Par défaut
    Sinon en poussant plus loin dans la réflexion tu peux récupérer les Constructors de tes classes et instancier ta classe à partir de ceux ci

  6. #6
    Membre Expert Avatar de herve91
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    1 282
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 1 282
    Par défaut
    Oui, je sais, mais je trouve dommage d'utiliser des mécanismes aussi lourds que la réflexion pour faire ça... SI on en arrive là, il me semble que ça traduit quand même une limite au concept d'héritage, non ?

  7. #7
    Membre éprouvé
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    94
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 94
    Par défaut
    Moi personnelement ca ne me choque pas du tout d'utiliser des 'instanceof' par contre il est clair qu'il faut centraliser la gestion j'aurais juste fait un Factory Method :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    public class PanelElementFactory{
     
    public static PanelElement newPanelElementInstance(Element e){
        if ( e instanceof ElementA ){
            return new PanelElementA(e);
        }
        else if ( e instanceof ElementB) {
             return new PanelElementB(e);
        }
        ...
    }
     
    }

  8. #8
    Membre expérimenté
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    319
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2006
    Messages : 319
    Par défaut
    Ahh, la propreté du code... ^^'

    Beaucoup s'accordent pour dire qu'instanceof doit être utilisé en dernier recours. Et comme le dit si bien Scott Meyers dans son ouvrage Effective C++ :

    «Anytime you find yourself writing code of the form "if the object is of type T1, then do something, but if it's of type T2, then do something else", slap yourself.»

    Autrement, herve91, je t'exposais juste le principe. Comme l'a ensuite dit sinok il est possible de passer des paramètres pour ce genre de construction.
    Les choses s'alourdissent en effet mais je ne pense pas qu'on atteigne une quelconque limite du concept d'héritage, on met plutôt un pied du côté de la réflexivité, ce qui, en soit, n'est pas la chose la plus évidente à aborder en termes de conception.


    Bon courage ! :]

  9. #9
    Membre averti
    Inscrit en
    Avril 2002
    Messages
    36
    Détails du profil
    Informations forums :
    Inscription : Avril 2002
    Messages : 36
    Par défaut
    Citation Envoyé par TigRoO°
    Ahh, la propreté du code... ^^'

    Beaucoup s'accordent pour dire qu'instanceof doit être utilisé en dernier recours. Et comme le dit si bien Scott Meyers dans son ouvrage Effective C++ :

    «Anytime you find yourself writing code of the form "if the object is of type T1, then do something, but if it's of type T2, then do something else", slap yourself.»

    Autrement, herve91, je t'exposais juste le principe. Comme l'a ensuite dit sinok il est possible de passer des paramètres pour ce genre de construction.
    Les choses s'alourdissent en effet mais je ne pense pas qu'on atteigne une quelconque limite du concept d'héritage, on met plutôt un pied du côté de la réflexivité, ce qui, en soit, n'est pas la chose la plus évidente à aborder en termes de conception.


    Bon courage ! :]
    Bon, il ne faut pas polluer le post en lançant un troll sur le sujet des instanceOf, mais si vous disposez des liens ou doc sur le sujet ça m'intéresse grandement, parce que j'ai un peu du mal avec l'affirmation intruduite hors contexte :

    Pour moi si tu veux éviter de traiter le typage d'un objet pour effectuer une action, tu es obligé de lui déléguer l'action en question :
    dans l'exemple du thread, pour associer un vue particulière à un type d'objet, soit tu te dois des résoudre la problématique : Quel est cet objet et quelle vue lui associer ? ou alors lui déléguer la responsabilité de te fournir le composant de vue qui convient.

    Je ne suis pas partisant de la délégation à outrance aux objets car même si c'est assez tentant d'un prime abord ca devient vite catastrophique en terme de maintenabilité et d'évolutivité, on a besoin de cloisonner les responsabilités et ne pas déléguer à tout va.
    Donc il reste à répondre à la première question. Mais on est déjà en contradiction avec ta citation.

    Et pour finir je dirais que c'est quelque chose qui est naturel et qui trouve son pendant dans le monde réel :
    quand on retire son courrier, si instanceOf publicité alors poubelle, je ne vois pas ce que ca a de choquant dans un monde objet.

    PS : si vous voulez poursuivre la discussion on ouvrira un nouveau post ^^

  10. #10
    Membre éprouvé
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    94
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 94
    Par défaut
    Bien que je ne sois pas Scott Meyers, je trouve plus propre une Factory Method qui utilise des instanceof qu'une Map d'association entre des classes et des factory, surtout pour une raison de lisibilité.

    De plus en Java il y a des APIs importantes avec lesquelles on est obligé d'utiliser des instanceOf comme JMS par exemple, le MessageConsumer ne connait pas forcément le type de Message et le seul moyen est d'utiliser du instanceof.

    Juste pour la petite histoire, les instanceof sont énormément utilisé dans les sources du jse, j'ai sur ma machine les sources de JAVA5 un rechercher sur les répertoires me donne 2123 classes utilisant ce keyword ce qui est considérable.

  11. #11
    Membre expérimenté
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    319
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2006
    Messages : 319
    Par défaut
    Oui, le mot-clé instanceof est pratique parfois, on est d'accord, mais il peut être évité avec une bonne conception OO. Je voulais surtout souligner une certaine divergence d'avis, au sein de la communauté, sur son usage. J'ai eu un maître de stage très à cheval sur la conception et la propreté du code et il me parlait de Scott et de son ouvrage à chaque discussion sur les bons principes... souvenirs !

    Le sujet originel ne porte pas sur les bonnes pratiques de programmation OO lando, en effet, pourquoi lances tu la discussion alors ? Surtout en fermant la porte derrière toi avec ton post-scriptum...


    Si ça intéresse du monde il y a, par exemple, ce sujet (en anglais) :

    http://forum.java.sun.com/thread.jsp...art=0&tstart=0

Discussions similaires

  1. Héritage, getClass, instanceof, casting
    Par tichadok dans le forum Langage
    Réponses: 3
    Dernier message: 29/05/2008, 17h56
  2. [Conception] héritage et overriding
    Par DranDane dans le forum Algorithmes et structures de données
    Réponses: 5
    Dernier message: 11/02/2008, 10h48
  3. Conception: héritage d'une classe abstraite
    Par Kikito dans le forum Langage
    Réponses: 19
    Dernier message: 05/10/2006, 17h36
  4. [conception] Héritage comment faire ?
    Par bohor2gannes dans le forum Modélisation
    Réponses: 11
    Dernier message: 15/02/2006, 17h35
  5. [heritage][conception]héritage multiple en java!
    Par soulhouf dans le forum Langage
    Réponses: 9
    Dernier message: 25/08/2005, 20h03

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo