Abstract

Abstract - Java - Programmation

Marsh Posté le 15-01-2017 à 22:11:53    

Bonjour, je suis novice en Java et j'aimerais solliciter votre aide pour le problème suivant :
 
J'essaie de coder quelque chose de " très simple ", un parc de véhicule.
J'ai une super-Classe " Vehicule " qui 2 classes-filles " AMoteur " et " SansMoteur ".  
AMoteur a 2 classes filles : " Voiture " et " Camion ".
SansMoteur a 1 classe fille : " Velo ".
 
Dans mon main, je crée les véhicules de cette manière :  

Code :
  1. Vehicule v1 = new Velo(...);
  2. Vehicule v2 = new Voiture(...);
  3. Vehicule v3 = new Camion(...);


Donc j'accède aux méthode de cette manière v1.maMethode()
 
Dans la classe Vehicule qui est une classe abstraite, il y a des méthodes abstraites qui sont implémentées dans les classes Filles.  
AMoteur et SansMoteur sont aussi des classes abstraites avec certaines méthodes de la classe Vehicule qui ont été implémentés mais d'autres méthodes de la classe Vehicule qui sont là aussi encore abstraites et seront implémentées dans les classes filles de AMoteur et SansMoteur.
 
Ma classe Vehicule :
 

Code :
  1. public abstract class Vehicule {
  2.    protected String nom;
  3.    protected double distanceParcourue;
  4.    public Vehicule(String n){
  5.     nom = n;
  6.     distanceParcourue = 0;
  7.    }
  8.    public String toString(){
  9.     return "-> Nom du Véhicule : "+nom+", Distance Parcourue : "+distanceParcourue+"mètres.\n";
  10.    }
  11.    public abstract void rouler(double distance);
  12.    public abstract void approvisionner(double nbLitres);
  13.    public abstract boolean enPanne();
  14.    public abstract void transporter(String depart, String arrivee); // 1
  15.    public abstract void transporter(int n, int km); // 2
  16.    public abstract void transporter(String materiau, int km); // 3
  17. }


 
Mon problème se situe sur les 5 dernières méthodes (pas rouler).
 
La méthode approvisionner est implémentée dans la classe AMoteur.
La méthode enPanne est implémentée dans la classe AMoteur.
La méthode transporter 1 est implémentée dans la classe Vélo qui a hérité de la classe abstraite SansMoteur.
La méthode transporter 2 est implémentée dans la classe Voiture qui a hérité de la classe abstraite AMoteur.
La méthode transporter 3 est implémentée dans la classe Camion qui a hérité de la classe abstraite AMoteur.
 
Comme vous le voyez elles sont implémentées dans différentes classes filles, sauf que, comme j'ai crée les méthodes abstraites dans la classe Vehicule alors toutes les classes filles doivent toutes les implémenter...
La classe SansMoteur hérite de la classe Vehicule, je dois donc y implémenter approvisionner et enPanne ainsi que transporter 2 et 3 obligatoirement. Bien évidemment, je n'ai aucun intérêt à le faire. Mais je suis obligé de les implémenter sinon ça ne fonctionne pas.
 
Avez-vous un moyen d'éviter cela ? Je sais exactement où est le problème, mais je n'arrive pas du tout à le contourner...

Reply

Marsh Posté le 15-01-2017 à 22:11:53   

Reply

Marsh Posté le 16-01-2017 à 10:25:00    

Toutes les méthodes d'une classe abstraite doivent obligatoirement être implémentées dans les classes filles, à la différence des méthodes virtual pour lesquelles ce n'est pas obligatoire.
Donc utilise une classe Vehicule non abstract, car par défaut en Java, toutes les méthodes non statiques sont virtuelles.


Message édité par Harkonnen le 16-01-2017 à 10:25:15

---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 16-01-2017 à 11:55:40    

Plus simplement il pourrait bouger les méthodes qui n'ont pas de sens dans Vehicule vers AMoteur par exemple.


---------------
click clack clunka thunk
Reply

Marsh Posté le 17-01-2017 à 01:12:17    

Justement DDT, si je bouge ces méthodes vers AM, je ne pourrais pas les utiliser avec une classe Vehicule. Je serais obligé de faire AMoteur v1 = new Voiture() et v1.approvisionner()...
 
Je cherche a accéder à toutes les méthodes avec la classe Vehicule.  
 
La seule solution que j'ai trouvé (depuis le début mais elle m'embête), c'est d'implémenter les méthodes partout où il faut et la liaison dynamique se charge du reste...
Mais c'est comme tricher et le code s'alourdit...
 
Harkonnen, est-ce que tu essayes de me dire de faire ça ? :
 

Code :
  1. public class Vehicule{
  2.    protected String nom;
  3.    protected double distanceParcourue;
  4.    public Vehicule(String n){
  5.       nom = n;
  6.       distanceParcourue = 0;
  7.    }
  8.   public String toString(){
  9.       return "-> Nom du Véhicule : "+nom+", Distance Parcourue : "+distanceParcourue+"mètres.\n";
  10.   }
  11.   public void approvisionner(double nbLitres){}
  12.   public void transporter(int n, int km){}
  13.   public void transporter(String materiau, int km){}
  14.   public void transporter(String depart, String arrivee){}
  15. }


 
Et je crée les mêmes méthodes dans les classes filles où elles doivent être et ainsi la liaison dynamique s'en charge aussi automatiquement ?
 
C'est ce que j'ai compris avec ton message, je l'ai fait et ça fonctionne parfaitement ! Dans le main :
 

Code :
  1. Vehicule v1 = new Voiture();
  2. Vehicule v2 = new Velo();
  3. Vehicule v3 = new Camion();
  4. v1.approvisionner(35);
  5. v3.approvisionner(20);
  6. v1.transporter("Dijon","Valence" );
  7. v2.transporter(5, 300);
  8. v3.transporter("tuiles", 1000);


 
Tout fonctionne correctement. J'y avais pas du tout pensé ! Merci encore. En espérant que c'est ce que tu essayais de me dire et que j'ai pas fait une bêtise...

Reply

Marsh Posté le 17-01-2017 à 08:47:00    

Oui, c'était ça.  
Par défaut en Java, toutes les méthodes non statiques sont virtuelles, ce qui veut dire que tu peux leur fournir une implémentation générique dans la classe mère et les redéfinir dans toutes les classes filles, mais ça n'est pas une obligation (à la différence des méthodes abstraites, qui, elles doivent obligatoirement être implémentées dans les classes dérivées).


---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 17-01-2017 à 11:54:17    

Kagaya a écrit :

Justement DDT, si je bouge ces méthodes vers AM, je ne pourrais pas les utiliser avec une classe Vehicule. Je serais obligé de faire AMoteur v1 = new Voiture() et v1.approvisionner()...
 
Je cherche a accéder à toutes les méthodes avec la classe Vehicule.  
 


OK, mais est-ce que ça a vraiment du sens?
 
Si tu fais ça:
 

Code :
  1. public void approvisionner(double nbLitres) {}


Tu as une méthode potentiellement sans effet, de manière silencieuse. Tu peux le documenter mais c'est pas terrible.
 

Code :
  1. public void approvisionner(double nbLitres) {
  2.     throw new UnsupportedOperationException("Méthode non-définie pour ce type de véhicule." );
  3. }


C'est un peu mieux.


---------------
click clack clunka thunk
Reply

Marsh Posté le 17-01-2017 à 13:26:17    

Moi quelque chose me gêne dans tout ça, et DDT a raison : pourquoi absolument vouloir tout mettre dans une classe Véhicule ? OK, un vélo est un véhicule, et une voiture est un véhicule. Mais une classe de base doit définir tous les comportements communs, à toutes ses sous-classes, et de toute évidence, la méthode approvisionner() n'est pas un élément commun, car un vélo n'a pas de réservoir à essence.

 

Pour moi, la classe Vehicule ne devrait définir que la méthode rouler(). Etant donné qu'il peut exister plusieurs façons de rouler pour un véhicule, on ne peut pas définir un comportement commun, donc cette classe devrait effectivement être abstraite comme dans le premier post.

 

Puis en fonction des différents comportements souhaités, on pourrait définir des interfaces correspondantes : une interface Motorisable qui contiendrait les méthodes approvisionner(), enPanne(), transporter2 et transporter3, et une interface NonMotorisable qui contiendrait la méthode transporter1.

 

Un exemple :

 
Code :
  1. // véhicule
  2. public abstract class Vehicule
  3. {
  4.   protected String nom;
  5.   protected double distanceParcourue;
  6.  
  7.   public Vehicule(String n){
  8.      nom = n;
  9.      distanceParcourue = 0;
  10.   }
  11.  
  12.   public String toString(){
  13.      return "-> Nom du Véhicule : "+nom+", Distance Parcourue : "+distanceParcourue+"mètres.\n";
  14.   }
  15.  
  16.   public abstract void rouler(double distance);
  17. }
  18.  
  19. // Motorisable
  20. public interface Motorisable
  21. {
  22.   public void approvisionner(double nbLitres);
  23.   public boolean enPanne();
  24.   public void transporter(int n, int km);
  25.   public void transporter(String materiau, int km);
  26. }
  27.  
  28. // NonMotorisable
  29. public interface NonMotorisable
  30. {
  31.   public void transporter(String depart, String arrivee);
  32. }
  33.  
  34. // vélo
  35. public class Velo extends Vehicule implements NonMotorisable
  36. {
  37.   public void rouler(double distance) {...}
  38.   public void transporter(String depart, String arrivee) {...}
  39. }
  40.  
  41. //voiture
  42. public class Voiture extends Vehicule implements Motorisable
  43. {
  44.   public void rouler(double distance) {...}
  45.   public boolean enPanne() {...}
  46.   public void approvisionner(double nbLitres) {...}
  47.   public void transporter(int n, int km) {...}
  48.   public void transporter(String materiau, int km) {...}
  49. }


Message édité par Harkonnen le 17-01-2017 à 23:56:52

---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 17-01-2017 à 16:48:15    

C'est ce que j'ai fait au début, mettre les méthodes communes dans les bonnes classes :

 

- La méthode rouler() dans la classe Véhicule.
- La méthode approvisionner() et enPanne() dans la classe AMoteur.
- La méthode transporter(int,int) dans la classe Voiture.
- La méthode transporter(string,int) dans la classe Camion.
- La méthode transporter(string,string) dans la classe Velo.

 

Avec la classe Véhicule comme classe mère, AMoteur et SansMoteur ses classes filles, et Velo,Voiture,Camion leurs classes filles. C'est ce que j'ai fait. Mais comme vous le savez, je ne peux pas accéder aux méthodes filles en créant un Vehicule v1...Seul v1.rouler pourra marcher. v1.approvisionner, transporter, etc...ne fonctionneront pas sauf si je crée des abstracts mais je vais devoir implémenter dans toutes les classes filles...

 

C'est la raison pour laquelle je suis venu poser la question ici. Je veux accéder à toutes les méthodes depuis une classe Principale : Vehicule.

 

C'est pour ça que j'aime bien la méthode de Harkonnen (les méthodes virtuelles) car je peux créer un Vehicule et le code va se charger AUTOMATIQUEMENT de trouver les bonnes méthodes en fonction du type de véhicule. Je peux ajouter des messages d'erreur au cas où. Après, je comprends que ça n'a pas de sens. Mais mon but était d'accéder à toutes les méthodes depuis la classe Vehicule (exercice de cours liaisons dynamiques), alors je pense que ce que m'a dit Harkonnen était le but de l'exercice.

 

J'ai essayé avec les interfaces, mais je peux pas accéder aux méthodes filles depuis la classe Vehicule. Je suppose que je dois créer le vehicule de cette manière : Motorisable voiture = new Voiture() ou encore, Voiture voiture new Voiture() pour accéder aux méthodes de Motorisable et Voiture ?

 


Message cité 1 fois
Message édité par Kagaya le 17-01-2017 à 16:50:04
Reply

Marsh Posté le 17-01-2017 à 21:24:48    

Bonjour, je connais trop peu java pour donner un conseil ici.
J'apporte juste une pierre à l'edifice OO.
 
Ne pourait-on pas voir les chose de la même manière, soit les même objet avec une autre PNL.
 
Par exemple : appeler roulant l'objet roulant et avoir une méthode transporter avec un parametre transporteur pouvant prendre energie parmis pousseur pour les fauteuil roulant, kérozen pour les volant, etc... et un paramêtre transporté pouvant prendre marchandise parmis objet individu, vide... etc.
 
Si quelq'un sait faire ça avec Ada, je suis preneur.

Reply

Marsh Posté le 17-01-2017 à 23:49:26    

Kagaya a écrit :

 

J'ai essayé avec les interfaces, mais je peux pas accéder aux méthodes filles depuis la classe Vehicule. Je suppose que je dois créer le vehicule de cette manière : Motorisable voiture = new Voiture() ou encore, Voiture voiture new Voiture() pour accéder aux méthodes de Motorisable et Voiture ?

 




Non, tout simplement comme ceci :

Code :
  1. public static void main(String[] args)
  2. {
  3.   Velo velo = new Velo();
  4.   Voiture voiture = new Voiture();
  5.  
  6.   velo.rouler(10);
  7.   voiture.rouler(15);
  8.   voiture.approvisionner(10);
  9.   velo.transporter("Bordeaux", "Paris" );
  10. }
 

Sinon, tu peux choisir d'instancier un Vehicule par exemple, et tester le type au runtime pour employer des méthodes spécifiques :

Code :
  1. public class Main {
  2.  
  3.    public static void main(String[] args) {
  4.       Vehicule velo = new Velo();
  5.       Vehicule voiture = new Voiture();
  6.  
  7.       velo.rouler(10);
  8.       voiture.rouler(15);
  9.  
  10.       if (voiture instanceof Motorisable)
  11.           ((Voiture)voiture).approvisionner(10);
  12.  
  13.       if (velo instanceof NonMotorisable)
  14.           ((Velo)velo).transporter("Bordeaux", "Paris" );
  15.    }
  16. }


Message édité par Harkonnen le 18-01-2017 à 00:08:40

---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 17-01-2017 à 23:49:26   

Reply

Marsh Posté le 19-01-2017 à 15:57:32    

Je vois, merci beaucoup, j'ai appris pas mal de choses grâce à ce post (notamment instanceof qui me facilite la gestion d'un tableau de Vehicule). J'ai testé avec les instanceof et ça règle tous les problèmes. Merci encore.

Reply

Marsh Posté le 19-01-2017 à 19:49:50    

You're welcome :)


---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 20-01-2017 à 11:51:09    

Kagaya a écrit :

Je vois, merci beaucoup, j'ai appris pas mal de choses grâce à ce post (notamment instanceof qui me facilite la gestion d'un tableau de Vehicule). J'ai testé avec les instanceof et ça règle tous les problèmes. Merci encore.


Fait gaffe quand même, instanceof c'est un antipattern et si tu l'utilises c'est le signe que ton design OO a un problème.
 


---------------
A religious war is like children fighting over who has the strongest imaginary friend.
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed