CONNEXION
  • RetourJeux
    • Sorties
    • Hit Parade
    • Les + populaires
    • Les + attendus
    • Soluces
    • Tous les Jeux
    • Gaming
  • RetourActu Gaming
    • News
    • Astuces
    • Tests
    • Previews
    • Toute l'actu gaming
  • RetourBons plans
    • Bons plans
    • Bons plans Smartphone
    • Bons plans Hardware
    • Bons plans Image et Son
    • Bons plans Amazon
    • Bons plans Cdiscount
    • Bons plans Decathlon
    • Bons plans Fnac
    • Tous les Bons plans
  • RetourJVTech
    • Actus High-Tech
    • Intelligence Artificielle
    • Smartphones
    • Mobilité urbaine
    • Hardware
    • Image et son
    • Tutoriels
    • Tests produits High-Tech
    • Guides d'achat High-Tech
    • JVTech
  • RetourCulture
    • Actus Culture
    • Culture
  • RetourVidéos
    • A la une
    • Gaming Live
    • Vidéos Tests
    • Vidéos Previews
    • Gameplay
    • Trailers
    • Chroniques
    • Replay Web TV
    • Toutes les vidéos
  • RetourForums
    • Hardware PC
    • PS5
    • Switch 2
    • Xbox Series
    • Switch
    • Pokemon pocket
    • FC 25 Ultimate Team
    • League of Legends
    • Tous les Forums
  • PC
  • PS5
  • Xbox Series
  • Switch 2
  • PS4
  • One
  • Switch
  • iOS
  • Android
  • MMO
  • RPG
  • FPS
En ce moment Genshin Impact Valhalla Breath of the wild Animal Crossing GTA 5 Red dead 2
Liste des sujets

[Java] héritage mulitple

dnob700
dnob700
Niveau 10
04 septembre 2010 à 13:21:19

(note de contexte : dans une semaine je commence à donner des cours de Java en L2 pour mon monitorat et je n'en ai jamais écrit une ligne de ma vie (bon, hier j'ai testé eclipse un peu)).

Bref, je sais bien que l'héritage multiple n'existe pas en java alors voici ce que j'aurais besoin de faire, si quelqu'un peut m'indiquer quelle est la bonne architecture pour ce faire je lui en serais reconnaissant.

Je veux fournir à mes élèves une classes leur simplifiant la gestion du réseau pour qu'il ne se pose pas cette question maintenant et j'aimerais qu'elle hérite de DataInputStream et de DataOutputStream, c'est-à-dire que la classe à un constructeur qui à la fin de son exécution va construire un objet DataInputStream et un DataOutputStream (branchés sur une communication réseau) et j'aimerais, sans que j'ai besoin de réécrire toutes ces fonctions que ma classe exporte directement toutes les fonctions membres de ses deux classes "parentes".

Est-ce possible ?

C'est peut-être idiot de vouloir faire ça (ma connaissance de la POO est très parcellaire au delà des grandes lignes), ne serait-ce que parce que certaine fonction membre doivent avoir le même nom. Et dans tout les cas, j'ai déjà fait autrement. Mais si c'est possible, je serais intéressé par savoir comment faire.

isukthar
isukthar
Niveau 10
04 septembre 2010 à 17:46:35

Moi je ferais de la délégation donc mettrais tout simplement une classe avec 1 attribut pour chaque classe dont tu veux hériter. Ou bien tu hérite de une et tu met l'autre en attribut.

dnob700
dnob700
Niveau 10
04 septembre 2010 à 18:28:08

Par délégation tu veux dire que je doit exporter dans ma classes des instances de chacune de ces classes ? Mais j'imagine qu'il faut un accesseur dans ce cas là pour que les utilisateurs ne puissent pas modifier l'instance de la classe qui est exporté.

Si c'est, ça vas être trop compliqué pour mon public. Là, j'ai juste redéfini quelques fonctions (celles dont ils ont vraiment besoin) que j'exporte, ce n'est peut-être pas le plus propre (même si ça me permet de faire un peu plus de traitement), mais c'est le plus simple je pense.

isukthar
isukthar
Niveau 10
04 septembre 2010 à 18:41:40

A l'instanciation de ta classe, tu va créer une instance de chacune de tes 2 classes comme attribut.
Après tu met juste les méthodes nécessaires qui font appel à l'attribut correspondant selon ce que tu veux autoriser à l'utilisateur.

Je ne comprend pas le "Mais j'imagine qu'il faut un accesseur dans ce cas là pour que les utilisateurs ne puissent pas modifier l'instance de la classe qui est exporté. ".
S'il n'y a pas d'accesseur, ils ne pourront rien modifier.

NoSoul_
NoSoul_
Niveau 7
04 septembre 2010 à 19:12:11

J'utiliserais plutôt les interfaces pour ce problème.

Une classe ne peut héritée que d'une seule classe, mais elle peut avoir plusieurs interfaces.

DataInputStream et DataOututStream sont des classes et pas des interfaces, mais elles implémentent respectivement les interfaces DataInput et DataOutput.

On peut donc faire une classe qui implémente ces deux interfaces et qui utilise en interne des objets DataInputStream et DataOutputStream pour l'implémentation.

Ce qui donne:

public class DataOutputInputStreams implements DataInput, DataOutput{

private DataInputStream dataIS;
private DataOutputStream dataOS;

public DataOutputInputStreams (InputStream is, OutputStream os) {
dataIS = new DataInputStream(is);
dataOS = new DataOutputStream(os);
}

...

}

J'ai mis un exemple un peu plus complet ici:

http://pastebin.ca/1932931

isukthar
isukthar
Niveau 10
04 septembre 2010 à 19:20:46

Ca dépend ce qu'il veut faire exactement, s'il a besoin de toutes les méthodes ou pas. Le problème dans les 2 cas c'est qu'il faut réécrire les fonctions d'au moins une des 2 classes.

NoSoul_
NoSoul_
Niveau 7
04 septembre 2010 à 20:06:58

Je suis d'accord mais comme il disait qui "exporte directement toutes les fonctions membres de ses deux classes "parentes"" c'est plus propre de mettre les interfaces.

S'il ne veut effectivement pas toutes les méthodes alors ta solution est plus simple.

Pseudo supprimé
Pseudo supprimé 05 septembre 2010 à 01:47:07

Si je peut me permettre, former tes étudiants à utiliser java à travers une "librairie" de ton cru me semble risqué d'un point de vue pédagogique.

Tu t'ajoutes une charge de travail, tu amènes des problèmes potentiels dues à ton implémentation, et surtout tu va former des étudiants à utiliser ta tambouille plutôt que l'API Java en elle même.

Mais bon, je ne suis pas enseignant, je n'émet qu'un avis d'ancien étudiant.

dnob700
dnob700
Niveau 10
05 septembre 2010 à 13:04:01

Tu as probablement raison DarkWings, sauf que le cours en question n'est pas un cours de programmation réseau, je ne suis pas sûr qu'ils ont déjà eu des cours de POO avant et je n'ai que peu d'heure pour leur dire ce qui constitue le cœur de mon cour. Donc, tout ce qui n'est pas essentiel, je préfère le leur donner (c'est un cours de programmation plus qu'un cours de Java).

Dans tout les cas ils ont par exemple aussi accès à des classes simplifiées pour faire des dessins ou à ce genre de chose.

Isuktar : "A l'instanciation de ta classe, tu va créer une instance de chacune de tes 2 classes comme attribut. Après tu met juste les méthodes nécessaires qui font appel à l'attribut correspondant selon ce que tu veux autoriser à l'utilisateur. "

Ce que tu me dis de faire, c'est la même chose que NoSoul_ mais sans les interfaces et donc en ne déclarant que les fonctions qui servent ? C'est comme ça que je vais le faire je pense, pour simplifier l'interface au maximum si de toutes manières je doit la définir moi même.

En tout cas merci à tous pour vos conseil.

saleGauss
saleGauss
Niveau 9
05 septembre 2010 à 15:31:52

Bonjour,

Tu m'as fais ressortir mes cours de POO avec Java, je me souvenais bien qu'on nous avait appris à éliminer l'héritage multiple entre classes.

l'idée, si tu veux créer C qui hérite de C1 et C2 c'est :

Prérequis : Il faut que C1 implémente l'interface I1, et C2 implémente l'interace I2 (ce qui est ton cas, car DataInputStream et DataOututStream implémentent respectivement DataInput et DataOutput)

- Tu crées une interface I qui hérite de I1 et I2.
- Ta classe C va hériter de C1, implémenter I, et contenir un objet de type C2.

Tu vas donc devoir ré-écrire tes fonctions de C2.
Systématiquement, elles ne feront qu'appeler la méthode de C2 sur l'objet interne de type C2.

Pourquoi avoir une classe I ?
Justement pour simuler ton héritage. Tu garantis que un objet de type C tient le contrat de I1 ET de I2, ce qui simule ton héritage avec C1 et C2.

Je pense qu'il n'y a malheureusement pas mieux pour simuler un héritage multiple...

saleGauss
saleGauss
Niveau 9
05 septembre 2010 à 15:35:41

Et tu remarqueras au passage pourquoi il est conseillé de toujours typer (lorsque c'est possible) des paramètres formels d'une fonction par une interface et non par une classe.

Considere une fonction f qui doit prendre un C2 en entrée.
Avec ma méthode du dessus, tu ne pourras pas lui passer un C, car C n'hérite pas de C2.

Par contre, si ta fonction prenait un I2 en entrée, là ça marche sans soucis.

Conclusion : Toujours typer au maximum par des interfaces.
Cela permet d'avoir plusieurs implémentations d'une même classe qui marcheront toutes pour cette fonction, ou de simuler un héritage multiple sans trop de soucis.

NoSoul_
NoSoul_
Niveau 7
05 septembre 2010 à 20:20:12

"- Tu crées une interface I qui hérite de I1 et I2. "

Il est impossible d'hériter de deux classes en Java, que ce soit une interface ou n'importe quoi d'autre. I peut par contre implémenter les interfaces I1 et I2.

"- Ta classe C va hériter de C1, implémenter I, et contenir un objet de type C2. "

C'est un joli cas théorique mais dans le cas où les deux classes possèdent la même relation avec la classe qu'on doit créer (comme dans le cas présent), je trouve ça génant.
Qu'est-ce-qui justifierait que DataOutputStream soit celle héritée et pas DataInputStream ? Du coup, autant les traiter de manière identique.

Ceci dit comme dnob700 n'a pas besoin de toutes les méthodes des deux classes, une approche du type "delegate" comme l'a proposé Isukthar me semble aussi la meilleure solution.

dnob700
dnob700
Niveau 10
05 septembre 2010 à 23:54:08

je suis d'accord sur l'asymétrie, je trouve ça gênant aussi. Au final, tout comme M. Jourdain, j'ai bien procédé par "delegate", même si je n'avais pas le nom à mettre sur cette approche.

saleGauss
saleGauss
Niveau 9
06 septembre 2010 à 17:26:45

NoSoul_, tu n'as pas bien lu ce que j'ai écris, et que tu as pourtant repris :

"Tu crées une interface I qui hérite de I1 et I2."
I1 et I2 sont des interfaces.

C1 et C2 sont les classes (dont on veut hériter), qui implémentent repectivement I1 et I2 b(c'était le pré-requis stipulé).

Je ne trouve pas que l'approche par delegate soit plus propre.
Avec "ma" méthode, au final, tout se passe réellement comme ci tu héritait des deux classes, à condition de typer par des interfaces...

NoSoul_
NoSoul_
Niveau 7
06 septembre 2010 à 18:38:39

Non non, j'ai bien lu. "I qui hérite de I1 et I2" c'est pas possible. Elle peut implémenter ("implements") mais elle peut pas hériter de I1 et I2.

saleGauss
saleGauss
Niveau 9
06 septembre 2010 à 20:34:58

Dans ce cas tu connais mal Java.

Essaie le code suivant :

// ICI la partie qui t'interesse particulierement
public interface I extends I1, I2{

}

public interface I1 {

}

public interface I2 {

}

public class C1 implements I1{

}

public class C2 implements I2{

}

public class C extends C1 implements I{
private C2 c2;

}

public class main {

public static void main(String[] args) {

I1 i1;

I2 i2;

C c = new C();

// ICI HERITAGE SIMULE, à condition de typer par des interfaces...
i1 = c;
i2 = c;

System.out.println("salut !");
}
}

Cela compile parfaitement.
je dois avouer que je n'aime pas particulierement quand on affirme avec une telle certitude quelque chose de faux.

Une CLASSE ne peut PAS étendre plusieurs CLASSES.
Une INTERFACE peut etendre plusieurs INTERFACES.
Une CLASSE peut implémenter plusieurs INTERFACES.
A retenir.

NoSoul_
NoSoul_
Niveau 7
06 septembre 2010 à 22:00:08

Effectivement je savais pas qu'on pouvait le faire.

J'ai pas insisté pour te contre dire mais pour comprendre ce que tu voulais dire. Et je dirais que j'ai bien fait vu que j'ai appris un truc que je savais pas.
Ceci dit ça aurait été plus sympa de marquer tout simplement qu'on peut faire de l'héritage multiple si ce sont des interfaces... ce que tu n'as pas fait avant.

NoSoul_
NoSoul_
Niveau 7
06 septembre 2010 à 22:19:46

Pour revenir au sujet, je ne vois pas toujours pas l'intérêt par rapport au code que j'ai mis plus haut:

public class DataOutputInputStreams implements DataInput, DataOutput{

private DataInputStream dataIS;
private DataOutputStream dataOS;

public DataOutputInputStreams (InputStream is, OutputStream os) {

dataIS = new DataInputStream(is);
dataOS = new DataOutputStream(os);

}

public void readFully(byte[] b) throws IOException {

dataIS.readFully(b);

}
...
}

De cette manière on garantit que toutes les méthodes sont présentes. La structure est plus simple. DataInputStream et DataOutputStream sont traités au même niveau.

Dans le code que tu mets y a le passage suivant que je n'aime pas:

public class C extends C1 implements I{
private C2 c2;

Pourquoi C1 et C2 doivent être traités différemment ? Qu'est-ce-qui le justifie ?

isukthar
isukthar
Niveau 10
06 septembre 2010 à 23:15:33

Pour moi la raison qui le justifierais c'est qu'on gagne du temps à ne pas ajouter les implémentations des méthodes de C1. C'est pas forcément judicieux mais ça fait gagner du temps.
La on est dans un cas où les élèves ne verront sûrement pas la différence, il faut juste faire au plus simple/rapide.

Mais sinon c'est vrai que les héritages multiples ça manque en Java. J'avais déjà eu ce problème sur un projet d'étude ou on avait potentiellement plein de classes de base et il fallait créer des classes qui héritaient de une ou plusieurs de ces classes de bases. Ca devient vite barbant de tout réécrire à chaque fois.

Bon après c'est sûr que l'héritage multiple dans le style C++ ça ajoute son lot de complexité avec les héritages virtuels, ... mais au moins on a le choix.

saleGauss
saleGauss
Niveau 9
06 septembre 2010 à 23:28:02

On y gagne juste qu'on ré-ecris la moitié des methodes.
C'est effectivement à peu près tout :-)

Je suis d'accord avec toi, ta structure est plus "propre" car plus symétrique.

Mais si les programmation orientation objet amenait naturellement à un code propre et cohérent, on le saurait depuis le temps... :-)

La POO est résumée dans ce thread.
Soit on fait ça en C++, et là on a de l'héritage multiple directement.
Mais le C++ apporte son lot de choses obscures, et d'absurdités qui le rend difficilement décidable.
Ou bien on fait ça en Java, mais en s'éloignant de la pensée UML des relations imposées (des héritages qui deviennent des relations associatives).

La POO, anthropomorphique ?

Sous forums
  • Aide à l'achat Mac
  • Création de sites web
  • Internet
  • Macintosh
  • Création de Jeux
  • Linux
  • Programmation
  • Steam Deck
  • Hardware
La vidéo du moment