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

avec Java Discussion :

Problème de design et d'héritage


Sujet :

avec Java

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Février 2011
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 99
    Points : 66
    Points
    66
    Par défaut Problème de design et d'héritage
    Bonjour,

    Je cherche à trouver la bonne architecture pour une partie de mon application.

    Voilà le problème :
    J'ai une classe Piece, donc étendent une classe Vis et une classe Clou.
    J'ai une classe Outils, dont étendent une classe Marteau et une classe Tournevis.

    Dans la classe Outils, je souhaite définir une méthode utiliserOutil(Piece piece). L'idée est que cette méthode soit redéfinie par les classes filles (Marteau et Tournevis), via un override ou une méthode abstraite.

    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
    public class Outils{
         utiliserOutil(Piece piece);
    }
     
    public class Marteau extends Outils{
     
         @Override
         utiliserOutil(Piece piece){
              ...
         }
    }
     
    public class Tournevis extends Outils{
     
          @Override
          utiliserOutil(Piece piece){
               ...
          }
    }
    J'ai ensuite une classe cliente, Atelier, qui possède une méthode :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    faireOperation(Outils outil, Piece piece){
         outil.utiliserOutil(piece);
    }
    Avec ce design, j'ai deux problèmes :
    - Rien n'empêchera plus le marteau d'utiliser la vis, ni le tournevis d'utiliser un clou dans la méthode faireOperation(...).
    - Dans la méthode utiliserOutils(Piece piece), je récupère un objet général Piece, et je ne peux plus le traiter spécifiquement comment une Vis ou un Clou.

    Je peux bien sûr envisager de faire un test dans chaque méthode via instanceof, puis de caster la Piece en Clou ou en Vis. Mais je cherche s'il n'existe pas un meilleure design.

    Avez-vous une idée de design qui puisse répondre à ce cas ?

    Je vous remercie par avance !

  2. #2
    Rédacteur/Modérateur
    Avatar de andry.aime
    Homme Profil pro
    Inscrit en
    Septembre 2007
    Messages
    8 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Ile Maurice

    Informations forums :
    Inscription : Septembre 2007
    Messages : 8 391
    Points : 15 059
    Points
    15 059
    Par défaut
    Bonjour,

    1-
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    public class Outils{
         utiliserOutil(Piece piece);
    }
    La classe Outils doit être abstraite si tu veux déclarer des méthodes sans implémentation à l'intérieur.

    2- Pour ton besoin, tu peux utiliser un interface. Tu peux voir un exemple ici.

    A+.

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Février 2011
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 99
    Points : 66
    Points
    66
    Par défaut
    Merci pour ta réponse, andry.aime.

    Effectivement pour fixer les choses, on peut dire que Outils est abstract, sinon mon code n'est pas correct.

    Par contre, je ne vois pas comment régler le problème en utilisant les interfaces. Même si je définie utiliserOutil(Piece piece) dans une interface, le problème restera le même : je devrai caster ma Piece en Clou ou en Vis au moment de la définition de la méthode.

    Ou alors, je n'ai pas compris comment tu me conseillais d'utiliser les interfaces. Peux-tu m'éclairer un peu dans ce cas s'il te plait ?

  4. #4
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    En fait, nous entrons plutôt là dans l'idée des génériques :

    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 interface Outils<P extends Piece> {
      void utiliserOutil(P piece);
    }
     
    public class Marteau implements Outils<Clou> {
     
      @Override
      public void utiliserOutil(Clou piece) {
        // TODO
      }
     
    }
     
    public class Tournevis implements Outils<Vis> {
     
      @Override
      public void utiliserOutil(Vis piece) {
        // TODO
      }
     
    }
    Puis dans l'atelier :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    public <P extends Piece> void faireOperation(Outils<? super P> outil, P piece){
      outil.utiliserOutil(piece);
    }
    Vérification :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public static void main(String... args) {
      Atelier atelier = new Atelier();
      atelier.faireOperation(new Marteau(), new Clou()); // ok
      atelier.faireOperation(new Tournevis(), new Vis()); // ok
      atelier.faireOperation(new Marteau(), new Vis()); // compile pas
    }
    C'est un exemple typique d'utilisation des génériques.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Février 2011
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 99
    Points : 66
    Points
    66
    Par défaut
    Merci pour cette réponse, thelvin, qui répond exactement à ce que je recherchais par rapport à mon problème !
    J'ai juste une question par rapport à ton code : à quoi sert le <? super P> dans la méthode faireOperation() de la classe Atelier ? On peut s'en passer a priori.


    J'ai encore un point qui me pose problème dans mon design.

    Imaginons que j'ai maintenant une classe Ponceuse, mais que celle-ci n'a pas de méthode utiliserOutil(Piece piece), car elle ne travaille pas sur une Piece.
    Cette classe n'implémente donc pas Outils<P>. Cependant, c'est un outils. Donc elle aura des points communs avec Marteau ou Tournevis. Par exemple, on pourrait avoir une méthode nettoyerOutils() que les outils Marteau, Tournevis et Ponceuse doivent implémenter (via par exemple une interface Nettoyable).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    public interface Nettoyable{
         void nettoyerOutil();
    }
    Dans ma classe Atelier, j'aurais alors une méthode :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    public <P extends Piece> void travaillerAvecOutils(Outils<P> outil, P piece){
         if(piece != null){
              outil.utiliserOutil(piece);
         }
     
         outil.nettoyerOutil(); //Erreur de compilation
    }
    Mais cela ne pourra pas fonctionner avec la Ponceuse (ni même avec le Marteau et le Tournevis d'ailleurs, puisque rien ne spécifie dans la méthode qu'ils sont Nettoyable).
    De la même manière, si j'utilise travaillerAvecOutils(Nettoyable nettoyable, Piece piece), je ne pourrais plus utiliser la méthode utiliserOutil(piece);
    Je suis donc coincé si tous mes outils n'héritent pas exactement des mêmes méthodes.

    Je peux toujours définir une interface générique puis tester via des instanceof si l'outil à tel ou tel propriété. Mais comme mon problème précédent, je recherche un meilleur design.

    De manière générale, comment puis-je avec une méthode générique dans Atelier (travaillerAvecOutils), traiter les différentes opérations que peuvent faire les outils, en sachant que tous les outils n'ont pas forcément les mêmes propriétés ?

  6. #6
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Citation Envoyé par bomehc Voir le message
    J'ai juste une question par rapport à ton code : à quoi sert le <? super P> dans la méthode faireOperation() de la classe Atelier ? On peut s'en passer a priori.
    Oui, on peut mettre juste Outils<P> mais c'est moins flexible.

    Parlons d'un nouvel outil : le Rangeur. C'est une baguette magique qui, quand elle touche une pièce d'un ouvrage, retire cette pièce, la répare et la nettoie, et va la ranger à sa place dans les pièces détachées. Ca marche avec tout : vis, clous, boulons, agrafe...

    Allons-y :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public class Rangeur implements Outils<Piece> {
      @Override
      public void utiliserOutil(Piece piece) {
        // TODO
      }
    }
    Il marche :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    atelier.faireOperation(new Rangeur(), new Vis());
    atelier.faireOperation(new Rangeur(), new Clou());
    Maintenant, j'ai repéré une vis dans l'espace de travail, et je sais que je dois en faire quelque chose, mais quel outil utiliser sur elle, c'est à débattre en fonction de la situation. J'ai une méthode choisirOutilPourVis() qui s'occupe de choisir, mais quel type doit-elle renvoyer ?

    Outils<Vis> ?

    Humm :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    public Outils<Vis> choisirOutilPourVis() {
      if(truc()) { // TODO
        return new Tournevis(); // ok
      } else {
        return new Rangeur(); // compile pas
      }
    }
    Alors Outils<Piece> ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    public Outils<Piece> choisirOutilPourVis() {
      if(truc()) { // TODO
        return new Tournevis(); // compile pas
      } else {
        return new Rangeur(); // ok
      }
    }
    Solution :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    public Outils<? super Vis> choisirOutilPourVis() {
      if(truc()) { // TODO
        return new Tournevis(); // ok
      } else {
        return new Rangeur(); // ok
      }
    }
    Maintenant essayons-le :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    atelier.faireOperation(choisirOutilPourVis(), new Vis());
    Si faireOperation() prenait un Outils<? super P> ça marche. S'il prend juste un Outils<P> ça ne marche pas.
    Le <? super P> permet de décrire plus précisément quels sont les cas qui devraient marcher.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  7. #7
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Citation Envoyé par bomehc Voir le message
    Imaginons que j'ai maintenant une classe Ponceuse, mais que celle-ci n'a pas de méthode utiliserOutil(Piece piece), car elle ne travaille pas sur une Piece.
    Cette classe n'implémente donc pas Outils<P>. Cependant, c'est un outils. Donc elle aura des points communs avec Marteau ou Tournevis. Par exemple, on pourrait avoir une méthode nettoyerOutils() que les outils Marteau, Tournevis et Ponceuse doivent implémenter (via par exemple une interface Nettoyable).
    A mon sens tu vas devoir réorganiser ta hiérarchie :

    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
    interface Outils {
      void nettoyerOutil();
    }
     
    interface OutilsSurPieces<P extends Piece> extends Outils {
      void utiliserOutil(P piece);
    }
     
    public class Marteau implements OutilsSurPieces<Clou> {
      void nettoyerOutil() {
        // TODO
      }
     
      void utiliserOutil(Clou piece) {
        // TODO
      }
    }
     
    public class Ponceuse implements Outils {
      void nettoyerOutil() {
        // TODO
      }
    }
    La ponceuse ne peut donc pas travailler sur une pièce. Mais tout comme les autres outils, tu peux la nettoyer quand tu as fini de t'en servir.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Février 2011
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 99
    Points : 66
    Points
    66
    Par défaut
    Merci thelvin pour cette explication très détaillée sur l'usage du <? super P>. C'est vraiment malin ! Et subtile !

    Pour mon second problème, je suis d'accord avec cette hiérarchie, mais elle ne permet pas de passer pour chaque outil dans la méthode :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    public void travaillerAvecOutils(Outils outil, P piece){
         if(piece != null){
              outil.utiliserOutil(piece);//Erreur de compilation
     
         }
     
         outil.nettoyerOutil(); 
    }
    En effet, j'aurai toujours une erreur de compilation vu que l'interface Outil n'a pas la méthode utiliserOutil(). Je suis donc obligé de caster dans ce cas en fonction de si l'outil étend également OutilsSurPiece.

    Est-ce qu'il est possible de passer en paramètre de cette méthode un Outil (ou un OutilManager peut-être ?) qui pourrait appeler les différentes action faisable par l'outil en fonction de si cet outil peut les faire ou pas ?
    Par exemple, si on passe la Ponceuse, on ne peut pas utiliser utiliserOutil(piece), mais on peut utiliser nettoyerOutil(). En revanche, si c'est le Marteau, il appelera les deux méthodes.
    Ou est-ce que le cast est la seule solution ?
    Le but étant que cette méthode soit générique.

  9. #9
    Membre du Club
    Profil pro
    Inscrit en
    Février 2011
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 99
    Points : 66
    Points
    66
    Par défaut
    Personne n'aurait une idée sur un design possible pour créer cette méthode ?

    Merci par avance.

  10. #10
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    J'avais pas vu.

    A partir du moment où une ponceuse ne peut pas travailler une pièce, elle ne devrait pas être utilisée dans une méthode qui prend une pièce en paramètre. Il faudrait prévoir une méthode pour le cas où on a une pièce à traiter et une méthode pour le cas où on n'en a pas. Passer null en paramètre, c'est nul.

    Mais si vraiment c'est ce que tu veux faire, alors c'est pas la peine de t'embêter : Ponceuse a qu'à devenir un Outils<Piece>, comme mon Rangeur. Et sa méthode utiliserOutil() n'a qu'à ne rien faire du tout, puisqu'elle ne sera pas appelée.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  11. #11
    Membre du Club
    Profil pro
    Inscrit en
    Février 2011
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 99
    Points : 66
    Points
    66
    Par défaut
    Merci thelvin.

    Dans le cas présent, le modèle est assez simple, et on pourrait imaginer effectivement avoir deux méthodes.

    Mais imaginons que le modèle se complexifie, que l'on traite d'avantage d'outils, et qu'ils se mettent à avoir des opérations communes deux à deux, et d'autres non.

    Par exemple, j'ajoute l'outil Lime (Ici, une lime à bois s'utilisant à la main).
    La Lime, comme le Marteau et le Tournevis, sont des OutilsManuel, par opposition à la Ponceuse qui est un OutilsElectrique.
    Mais, la Lime et la Ponceuse sont des OutilsSurBois, par opposition au Marteau et Tournevis qui sont des OutilsSurPiece.

    On a donc les interfaces suivantes :

    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
    interface OutilsSurBois extends Outils{
         void nettoyerOutil();
    }
     
    interface OutilsSurBois extends Outils{
         void travaillerBois();
    }
     
    interface OutilsSurPieces<P extends Piece> extends Outils {
         void utiliserOutil(P piece);
    }
     
    interface OutilsManuel extends Outils {
         void saisirOutil();
    }
     
    interface OutilsElectrique extends Outils {
         void allumerCourant();
    }
    Et côté modèle :

    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
    public class Marteau implements OutilsSurPieces<Clou>, OutilsManuel{
    ...
    }
     
    public class Tournevis implements OutilsSurPieces<Vis>, OutilsManuel{
    ...
    }
     
    public class Lime implements OutilsSurBois, OutilsManuel{
    ...
    }
     
    public class Ponceuse implements OutilsSurBois, OutilsElectrique{
    ...
    }
    On peut continuer à étendre (en ajoutant par exemple le Rangeur) ...

    Côté Atelier, on a bien un utilisateur qui va vouloir utiliser un outil (avec éventuellement une pièce).
    Comment traiter le cycle de vie de l'utilisation d'un outil en fonction de l'outil ?


    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
    public void travaillerAvecOutils(Outils outil, P piece){
         if (outil instanceof OutilsManuel){
              ((OutilsManuel) outil).saisirOutil();
         }else if (outil instanceof OutilsElectrique){
              ((OutilsElectrique) outil).allumerCourant();
         }
     
         if(piece != null){
              outil.utiliserOutil(piece);
         }else if (outil instanceof OutilsSurBois){
              ((OutilsSurBois) outil).travaillerBois();
         }
     
         outil.nettoyerOutil(); 
    }
    A termes, on est donc obligé de caster à chaque opération, chaque outil ayant bien son comportement pour une opération donnée.
    Cependant, les outils ont bien un cycle d'utilisation (préparation, action, nettoyage, ...).
    C'est là ou je m'interroge pour savoir s'il n'y a pas mieux que de devoir faire des castes à chaque opération, la méthode des génériques ayant
    déjà répondu à un aspect du problème.

    Y aurait-il un meilleur design, ou des pistes pour modéliser ce problème ?

  12. #12
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    A partir du moment où tu as des interfaces indépendantes OutilsManuel et OutilsElectrique, et que le fait d'en implémenter une implique de devoir utiliser une méthode de plus, on part dans des cas pathologiques.
    Il n'y a pas une solution à tout.

    Nous pourrions envisager d'étendre Outils :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    interface Outils {
      void preparerOutil();
      void nettoyerOutil();
    }
    Et décider que toute implémentation de OutilsManuel a pour charge d'appeler saisirOutil() au cours de preparerOutil().
    De même les implémentations de OutilsElectrique doivent appeler allumerCourant().
    Nous ne pouvons pas le forcer au niveau du compilateur. C'est le programmeur qui, quand il les implémente, doit être conscient de ce contrat et doit l'implémenter.

    Pour simplifier, nous pouvons définir des classes abstraites :

    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 abstract class AbstractOutilsManuel implements OutilsManuel {
      @Override
      public void preparerOutil() {
        saisirOutil();
      }
    }
     
    public abstract class AbstractOutilsElectrique implements OutilsElectrique {
      @Override
      public void preparerOutil() {
        allumerCourant();
      }
    }
     
    public abstract class AbstractOutilsManuelElectrique implements OutilsElectrique, OutilsManuel {
      @Override
      public void preparerOutil() {
        allumerCourant();
        saisirOutil();
      }
    }
    Et les classes concrètes deviennent :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    public class Marteau extends AbstractOutilsManuel implements OutilsSurPieces<Clou> {
     
    public class Ponceuse extends AbstractOutilsElectrique implements OutilsSurBois {
     
    public class ScieCirculaireAMain extends AbstractOutilsManuelElectrique implements OutilsSurBois {
    La méthode travaillerAvecOutils() devient alors :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public void travaillerAvecOutils(Outils outil, P piece){
        outil.preparerOutil();
     
         if(piece != null){
              outil.utiliserOutil(piece);
         }else if (outil instanceof OutilsSurBois){
              ((OutilsSurBois) outil).travaillerBois();
         }
     
         outil.nettoyerOutil(); 
    }
    Voilà pour les deux premiers instanceof.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  13. #13
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Concernant le reste des instanceof, je continue de penser que si un outil ne travaille pas sur une pièce, alors il n'a rien à faire dans une méthode qui prend une pièce en paramètre.

    Là tu nous dis que quand il ne bosse pas sur une pièce, il doit bosser sur le bois à la place. Bon, du coup ça fait quand même penser que le bois c'est une pièce comme les autres. Enfin, admettons que ce soit plus compliqué que ça.
    Du coup, ce qu'il y a à faire, c'est un travail. Soit du travail sur bois, sotr du travail sur une pièce. Et on cherche à faire que le compilateur vérifie que l'outil choisi soit compatible avec le travail choisi.
    C'est la même chose que pour vérifier clou <-> marteau et vis <-> tournevis, sauf que travailler sur le bois c'est pas travailler sur une pièce. Donc on va à nouveau utiliser les génériques, mais en séparant les deux concepts

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    interface Outils<T extends Travail> {
      void utiliserOutil(T travail);
      void nettoyerOutil();
    }
    Avec

    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
    interface Travail {
      // rien a priori. C'est juste un parent entre travail sur bois ou sur piece
    }
     
    public final class TravailSurBois implements Travail {
      public static final TravailSurBois INSTANCE = new TravailSurBois();
      /** Un singleton suffit */
      private TravailSurBois() {}
    }
     
    public class TravailSurPiece<P extends Piece> implements Travail {
     
      private final P piece;
      public TravailSurPiece(P piece) {
        this.piece = piece;
      }
     
      public P getPiece() {
        return piece;
      }
     
    }
    On a des outils :

    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
    public class Ponceuse extends AbstractOutilsElectrique<TravailSurBois> {
      @Override
      void utiliserOutil(TravailSurBois ignore) {
        travaillerLeBois();
      }
      void travaillerLeBois() {
        // TODO
      }
    }
     
    public class Marteau extends AbstractOutilsManuel<TravailSurPiece<Clou>> {
      @Override
      void utiliserOutil(TravailSurPiece<Clou> travail) {
        utiliserOutil(travail.getPiece());
      }
      void utiliserOutil(Clou clou) {
        // TODO
      }
    }
    et notre méthode devient :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public <T extends Travail> void travaillerAvecOutils(Outils<? super T> outil, T travail){
        outil.preparerOutil();
        outil.utiliserOutil(travail);
        outil.nettoyerOutil(); 
    }
     
    {
      atelier.travaillerAvecOutils(new Ponceuse(), TravailSurBois.INSTANCE);
      atelier.travaillerAvecOutils(new Marteau(), new TravailSurPiece<Clou>(new Clou()));
      atelier.travaillerAvecOutils(new Tournevis(), new TravailSurPiece<Clou>(new Clou())); // compile pas
    }
    Les choses se compliquent, mais continuent de marcher pour l'instant.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  14. #14
    Membre du Club
    Profil pro
    Inscrit en
    Février 2011
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 99
    Points : 66
    Points
    66
    Par défaut
    Merci beaucoup pour tous ces exemples détaillés, thelvin. Je comprends mieux comment utiliser les génériques maintenant, et comment designer une application qui les utilise.
    On peut faire des choses assez poussées avec en fait !
    Merci pour le temps que tu as passé sur mon problème !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. problème mode design Asp.net[2.0]
    Par dev-man dans le forum ASP.NET
    Réponses: 6
    Dernier message: 07/02/2007, 14h05
  2. [GRIDBAGLAYOUT] problème entre design et execution
    Par Lambrosx dans le forum NetBeans
    Réponses: 5
    Dernier message: 04/12/2006, 15h35
  3. Problème de design !
    Par franck.thibault dans le forum Balisage (X)HTML et validation W3C
    Réponses: 1
    Dernier message: 25/08/2006, 14h23
  4. [Hibernate]Problème pour mapping d' un héritage
    Par K-Kaï dans le forum Hibernate
    Réponses: 6
    Dernier message: 29/06/2006, 14h28
  5. Problème de design
    Par b4u dans le forum C++
    Réponses: 4
    Dernier message: 10/03/2006, 00h50

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