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 d'une classe abstraite


Sujet :

Langage Java

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

    Informations forums :
    Inscription : Mars 2005
    Messages : 94
    Points : 102
    Points
    102
    Par défaut Conception: héritage d'une classe abstraite
    Bonjour,
    Je me pose la question suivante, quelle est la meilleure manière de développer le cas suivant :
    - une classe abstraite n'a pas de valeur pour un certain champs
    - les enfants (qui sont plusieurs ) ont ce champs et il a une valeur
    - ce champs est final
    - le getChamps fait toujours la même chose

    Feriez vous :

    1)
    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
    abstract class 1{
        final int idType;
    ...
        public getIdType(){
            return idType;
        }
        protected 1(int idType){
            this.idType = idType;
        }
    }
    class 2 extends 1{
    ...
        public 2(){
            super(valeur_de_l'id_type);
        }
    }
    ou :

    2)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    abstract class 1{
        public abstract getIdType();
    }
    class 2 extends 1{
        final int idType = 5;
    ...
       public getIdType(){
            return idType;
        }
    }
    Ou autre chose ?

    Dans le 1) ce qui m'embete c'est qu'on perd en lisibilité et qu'on définit la variable final dans le constructeur, et dans le 2) c'est de devoir écrire n fois la même fonction getIdType(), bref aucune des deux solutions ne me satisfait.

    Que feriez vous ?

  2. #2
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    365
    Détails du profil
    Informations personnelles :
    Localisation : Maroc

    Informations forums :
    Inscription : Janvier 2006
    Messages : 365
    Points : 495
    Points
    495
    Par défaut
    Bonjour
    Moi je rendrais plutôt le champ protected pour qu'il soit hérité par les sous classes, et donc elles pourront l'initialiser dans leur constructeur. Ce serait quelque chose comme :
    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
     
    abstract class 1{
        protected final int idType;
    ...
        public getIdType(){
            return idType;
        }    
    }
     
    class 2 extends 1{
    ...
        public 2(int val){
            this.idType = val;
        }
    }
    Je ne l'ai pas testé, donc je ne sais pas si le fait que le champ soit final pourrait faire que le code ne donne pas le résultat attendu. Si tu peux me donner un retour pour ça.
    SCJP 5 / SCBCD 1.3 Certified

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    365
    Détails du profil
    Informations personnelles :
    Localisation : Maroc

    Informations forums :
    Inscription : Janvier 2006
    Messages : 365
    Points : 495
    Points
    495
    Par défaut
    Bon, je viens de tester rapidement le code que j'ai donné ci-dessus, et comme je le soupçonnais, il y a effectivement une erreur de compilation due au fait que le champ est final et ne peut plus être assigné une nouvelle fois dans les sous-classes. Donc pour que la solution marche, il faudrait enlever le modificateur final pour le champ. Cela étant, puisque c'est une question de conception, je me demande pourquoi tu as besoin que ce champ soit final, il suffirait qu'il soit private et que la classe ne fournisse que la méthode "getChamp". Et comme il n'y aurait pas de "setChamp", il n'y aurait aucune chance qu'une nouvelle valeur soit affectée à ce champ de l'extérieur de la classe, donc tout resterait sous contrô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
    16
    17
    18
     
    abstract class 1{
        private int idType;
     
        protected 1 (int val){
             this.idType = val;
        }
        public int getIdType(){
            return idType;
        }    
    }
     
    class 2 extends 1{
    ...
        public 2(int value){
            super(value);
        }
    }
    Voilà ce que je peux en dire. Sinon, pour les deux solutions que tu as proposées, la première me satisferait plus que la deuxième.
    SCJP 5 / SCBCD 1.3 Certified

  4. #4
    Membre habitué Avatar de BlackWood
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    167
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 167
    Points : 169
    Points
    169
    Par défaut
    De même, je pense que la première solution est meilleure.
    J'aurai cependant combiné private et final :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public abstract class AbstractClass {
    
    	private final int var;
    	
    	protected AbstractClass(int var) {
    		this.var = var;
    	}
    	
    	public final int getVar() { return var;}
    }
    BlackWood
    Et comme apparemment, ça fait "class" dans une signature :
    , , , ,

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    365
    Détails du profil
    Informations personnelles :
    Localisation : Maroc

    Informations forums :
    Inscription : Janvier 2006
    Messages : 365
    Points : 495
    Points
    495
    Par défaut
    Je pense que tu as raison de mettre final la méthode "getVar" , ça empêcherait toute redéfinition par les sous-classes. C'est ce qui est fait d'ailleurs pour les Enum. Chaque type enum créé hérite de la classe java.lang.Enum, peut redefinir "toString()" mais pas "name()" qui pourtant donne la même valeur pour la classe mère. Bon, je m'éloigne un peu peut-être ...
    SCJP 5 / SCBCD 1.3 Certified

  6. #6
    Membre habitué Avatar de BlackWood
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    167
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 167
    Points : 169
    Points
    169
    Par défaut
    Mais non, toute précision est la bienvenue !
    BlackWood
    Et comme apparemment, ça fait "class" dans une signature :
    , , , ,

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

    Informations forums :
    Inscription : Mars 2005
    Messages : 94
    Points : 102
    Points
    102
    Par défaut
    Merci de vos réponses, je pense qu'effectivement dans le cas que j'expose la solution est la meilleure, toutefois mon problème est que j'ai pas mal de variables dans ce cas et que je ne veux pas d'un constructeur à 50 niveaux, j'ai opté pour une solution un peu "batarde".
    Dans le parent je mets les int à -1 et les Object à null, le set du parent ne pouvant se faire que si la valeur est égal à -1 pour un int ou null pour un objet, c'est du semi final dirons nous.
    Considérez-vous cette solution comme convenable ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public abstract class AbstractClass {
    	private int var = -1;
    	private String var2 = null;
     
    	public final int getVar() { return var;}
    	public final String getVar2() { return var2;}
    	protected final void setVar(int new){
    		if (var == -1 ){var = new;}
    	}
    	protected final void setVar2(String new){
    		if (var == null ){var2 = new;}
    	}
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    public class Enfant extends AbstractClass {
     
    	public Enfant(){
    		setVar(int);
    		setVar2(string);
    	}
    }

  8. #8
    Membre habitué Avatar de BlackWood
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    167
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 167
    Points : 169
    Points
    169
    Par défaut
    Mouais...
    C'est assez spécial mais ça devrait marcher.
    J'essaie de trouver des inconvénients, mais je n'en vois pas vraiment, mis à part le coté "batard", comme tu dis...
    Si, le problème, c'est que cette solution n'empèche pas de refaire un setVar() par la suite, même si rien ne se passera.
    Au pire, lance une Exception si la variable n'est pas null ou égale à -1. Mais bon.
    BlackWood
    Et comme apparemment, ça fait "class" dans une signature :
    , , , ,

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

    Informations forums :
    Inscription : Mars 2005
    Messages : 94
    Points : 102
    Points
    102
    Par défaut
    Oui c'est ce que j'ai fait, j'ai synthétisé là dans l'exemple.

    Je sais que c'est bizarre, mais vu mon cas je ne trouve rien de mieux, la solution que tu préconises est bien mais fonctionne bien si on a seulement 1 ou 2 variables à passer.
    Le constructeur à 10 arguments ça me plait encore moins.

    Ceci dit c'est vrai que c'est pas génial, je suis toujours preneur d'une meilleure solution

  10. #10
    Membre chevronné
    Avatar de professeur shadoko
    Homme Profil pro
    retraité nostalgique Java SE
    Inscrit en
    Juillet 2006
    Messages
    1 257
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 75
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : retraité nostalgique Java SE

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 257
    Points : 1 855
    Points
    1 855
    Par défaut
    j'a pas tout compris est ce que queque chose dans cet esprit te conviendrait:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    abstract class AbstractClass <X,Y> {
        private final X x;
        private final Y y ;
     
       protected AbstractClass(X x, Y y) {
        ....
    }
    et après
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    class Fille extends AbstractClass<String, Integer> {
     ...
    }
    bon il y a des limitations c'est juste pour brainstormer ...
    J'ai des principes: je peux toujours trouver une bonne raison pour les contredire .... mais j'ai des principes!
    (mon excellent bouquin sur Java : https://eska-publishing.com/fr/livre...822407076.html)

  11. #11
    Membre habitué Avatar de BlackWood
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    167
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 167
    Points : 169
    Points
    169
    Par défaut
    Citation Envoyé par professeur shadoko
    j'ai pas tout compris est ce que queque chose dans cet esprit te conviendrait:
    Non, il ne me semble pas que ce soit ce qu'il cherchait à faire...
    Ce n'était pas un problème de type de variable mais de marqueur (final), comme dit plus haut.
    BlackWood
    Et comme apparemment, ça fait "class" dans une signature :
    , , , ,

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

    Informations forums :
    Inscription : Mars 2005
    Messages : 94
    Points : 102
    Points
    102
    Par défaut
    Et que pensez vous d'utiliser la réflection ?

    En faisant dans le constructeur de la classe abstraite appel aux Fields de la classe de l'object :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public abstract class AbstractClass {
    	final Obj var;
     
    	public AbstractClass(){
    		var = (Obj)this.getClass().getField("var").get(Obj.class);
    	}
    }
     
    public class 2 extends AbstractClass {
    	public static final Obj var = "toto";
    }

  13. #13
    Membre habitué Avatar de BlackWood
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    167
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 167
    Points : 169
    Points
    169
    Par défaut
    Houuu ! Là par contre, tu t'éloignes à mon avis. Je pense que la réflection ne devrait être utilisée qu'en dernier recours, dans un ou deux cas vraiment spéciaux. Je préférais la version précédente.

    Faudrait d'autres opinions...
    BlackWood
    Et comme apparemment, ça fait "class" dans une signature :
    , , , ,

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

    Informations forums :
    Inscription : Mars 2005
    Messages : 94
    Points : 102
    Points
    102
    Par défaut
    Possible, y a toujours un truc qui me chiffonne dans les solutions que j'ai trouvé.

    Sinon y aurait ne pas faire exister les valeurs en tant que variable mais juste les mettre au sein de get dans les classes enfants :

    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
    public abstract class AbstractClass {
     
    	public abstract int getVar1();
    	public abstract String getVar2();
    	...
    }
     
    public class 2 extends AbstractClass {
    	public int getVar1(){
    		return 5;
    	}
    	public String getVar2(){
    		return "toto";
    	}
     
    }
    public class 3 extends AbstractClass {
    	public int getVar1(){
    		return 6;
    	}
    	public String getVar2(){
    		return "titi";
    	}
     
    }
    La c'est le coté maintenance qui est fatiguant

    Ceci étant comme tu le dis, ça serait bien d'avoir plusieurs opinions, y a pas un design pattern pour ce cas ?

  15. #15
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,


    Perso je trouve que c'est ta première solution de ton premier post qui est la plus propre :
    • Ton champs est final.
    • En définissant la méthode getChamps() final, tu es sûr que son comportement ne sera pas altéré dans les classes filles.
    • Tu es sûr que toutes les classes filles auront défini une valeur.

    Qu'est-ce qui te dérange dans cette solution ???

    a++

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

    Informations forums :
    Inscription : Mars 2005
    Messages : 94
    Points : 102
    Points
    102
    Par défaut
    Ce qui me dérange c'est que je n'ai pas une mais plusieurs variables dans ce cas, et que je n'aime pas trop le constructeur à 10 arguments.
    Avoir de multiples set dans la classe enfant ( ou faire aller chercher les données à la classe abstraite ) rendrait le code plus lisible et maintenable.

  17. #17
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Kikito
    Ce qui me dérange c'est que je n'ai pas une mais plusieurs variables dans ce cas, et que je n'aime pas trop le constructeur à 10 arguments.
    L'avantage c'est que tu es sûr que tous les champs seront initialisé correctement, sinon tu auras une erreur de compilation...

    Citation Envoyé par Kikito
    Avoir de multiples set dans la classe enfant
    Dans ce cas la seule solution serait celle que tu as décrites avec les pseudo-final et les méthodes set() qui ne fonctionne qu'une seule fois...

    Citation Envoyé par Kikito
    ( ou faire aller chercher les données à la classe abstraite )
    Tu pourrais éventuellement utiliser la reflection et un fichier properties voir des annotations qui contiendrais les données...

    a++

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

    Informations forums :
    Inscription : Mars 2005
    Messages : 94
    Points : 102
    Points
    102
    Par défaut
    J'avais proposé un code utilisant la réflection (qqposts au dessus), sans properties mais en déclarant les variables public static final.
    Qu'en pensais-tu ?

  19. #19
    Membre habitué Avatar de BlackWood
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    167
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 167
    Points : 169
    Points
    169
    Par défaut
    Comme je t'avais dit, et comme a dit Guba ( ), la première reste quand même la meilleure des solutions, à savoir :
    public abstract class AbstractClass {

    private final int var;

    protected AbstractClass(int var) {
    this.var = var;
    }

    public final int getVar() { return var;}
    }
    T'aime pas trop les constructeurs à 10 arguments. C'est compréhensible, moi de même. Mais pour ce coup-là, disons, pour ce que tu cherches, c'est encore ce qu'il y a de mieux. Si c'est une question de lisibilité, tu n'a qu'à mettre d'un argument par ligne, ça ne sera pas pire que de les initialiser un par un...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    super(	int var1,
    	int var2,
    	int var3,
    	...
    	);
    A toi de voir...
    BlackWood
    Et comme apparemment, ça fait "class" dans une signature :
    , , , ,

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

    Informations forums :
    Inscription : Mars 2005
    Messages : 94
    Points : 102
    Points
    102
    Par défaut
    Bah on voit ce qu'on passe par le nom du set, c'est pas trop le fait que ce soit sur une ligne ou pas qui rend le code lisible.
    setAge(26);
    setNbrEnfants(2);
    setNom("Dupond");
    ...
    n'est pas

    super(
    26,
    2,
    "Dupond",
    ...
    );

    Mais bon vous devez avoir raison

Discussions similaires

  1. Réponses: 4
    Dernier message: 27/09/2012, 17h37
  2. héritage d'une classe abstraite
    Par new_wave dans le forum Langage
    Réponses: 8
    Dernier message: 04/03/2010, 12h54
  3. [Conception] Héritage sur Plusieurs classes abstraites
    Par facilus68 dans le forum Langage
    Réponses: 9
    Dernier message: 20/03/2009, 13h06
  4. Problème d'héritage avec une classe abstraite
    Par Ph.denis dans le forum C++
    Réponses: 7
    Dernier message: 22/03/2008, 10h37
  5. Erreur du designer avec héritage d'une classe abstraite
    Par Xzander dans le forum Windows Forms
    Réponses: 4
    Dernier message: 04/04/2007, 00h36

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