OVH Cloud OVH Cloud

[méthode de programmation] surcharge et typage

9 réponses
Avatar
Ced
Salut a tous!

Les 2 premieres questions que j'ai envoyé sur ce newsgroup n'ont jamais eu
de réponse. J'espère être plus chanceux cette fois ci...

J'ai une classe qui contient une méthode moult fois surchargée:

Classe1 {
void methode1(Objet o) {...}
void methode1(Integer o) {...}
void methode1(String o) {...}
void methode1(AutreObjet o) {...}
}

Cette classe permet de gérer le comportement de l'appli en fonction du type
passé. L'appelant n'a pas à se soucier de quoi que ce soit.

J'ai une deuxième classe qui contient la méthode suivante:

Classe 2 {

methode2 (Objet o) {
...
objetDeClasse1.methode1(o);
}

Le problème est que dans ce cas, c'est toujours la première méthode de
Classe1 (void methode1(Objet o)) qui est appelée, même lors d'un:
objetDeClasse2.methode2(new Integer(5));

Une parade consiste à aller chercher la méthode adéquate avec un
getClass().getMethod(), mais cela me parait lourd et risqué: il peut y avoir
des erreurs dans le nom de la méthode, puis à l'exécution, et il faut de
suite gerer 3 exceptions... :(

N'y aurait-il pas moyen de faire un cast dynamique? Je n'ai pas trouvé
d'infos sur le sujet.
Ma méthode2 s'écrirait alors dans le genre:

methode2 (Objet o) {
...
objetDeClasse1.methode1( (o.getClass()) o );
}

ce qui serait beaucoup plus simple à gérer, et plus propre à mon avis. Ou
alors dois-je revoir entièrement la structure de mon programme? Je cherche à
faire quelque chose de propre. Quelqu'un a une idée?

Merci d'avance pour votre aide.

Ced.

9 réponses

Avatar
captainpaf
Le Wed, 29 Oct 2003 08:46:58 +0100, "Ced" a écrit
:

Salut a tous!

Les 2 premieres questions que j'ai envoyé sur ce newsgroup n'ont jamais eu
de réponse. J'espère être plus chanceux cette fois ci...

J'ai une classe qui contient une méthode moult fois surchargée:


Surcharger trop souvent une méthode c'est rarement bon signe.... Mais
bon, il y a des exceptions à la règle.


Classe1 {
void methode1(Objet o) {...}
void methode1(Integer o) {...}
void methode1(String o) {...}
void methode1(AutreObjet o) {...}
}

Cette classe permet de gérer le comportement de l'appli en fonction du type
passé. L'appelant n'a pas à se soucier de quoi que ce soit.

J'ai une deuxième classe qui contient la méthode suivante:

Classe 2 {

methode2 (Objet o) {
...
objetDeClasse1.methode1(o);
}

Le problème est que dans ce cas, c'est toujours la première méthode de
Classe1 (void methode1(Objet o)) qui est appelée, même lors d'un:
objetDeClasse2.methode2(new Integer(5));



Ben jusque là tout me parait logique, o est et reste un objet si tu ne
le cast pas.

Une parade consiste à aller chercher la méthode adéquate avec un
getClass().getMethod(), mais cela me parait lourd et risqué: il peut y avoir
des erreurs dans le nom de la méthode, puis à l'exécution, et il faut de
suite gerer 3 exceptions... :(

N'y aurait-il pas moyen de faire un cast dynamique? Je n'ai pas trouvé
d'infos sur le sujet.
Ma méthode2 s'écrirait alors dans le genre:

methode2 (Objet o) {
...
objetDeClasse1.methode1( (o.getClass()) o );
}

ce qui serait beaucoup plus simple à gérer, et plus propre à mon avis. Ou
alors dois-je revoir entièrement la structure de mon programme? Je cherche à
faire quelque chose de propre. Quelqu'un a une idée?

Merci d'avance pour votre aide.

Ced.


Le mieux peut être serait que tu nous dises ce que ton programme dois

faire afin de trouver une solution simple et propre à ton problème.

Avatar
Nicolas Delsaux
Le Wed, 29 Oct 2003 08:46:58 +0100, Ced s'est levé est s'est dit : "tiens,
si j'écrivais aux mecs de fr.comp.lang.java :

Salut a tous!

Les 2 premieres questions que j'ai envoyé sur ce newsgroup n'ont jamais eu
de réponse. J'espère être plus chanceux cette fois ci...


C'est peut-être que ces questions n'étaient pas intéressantes, ou que
personne n'avait le temps d'y répondre, voire mêe que personne ne les a
compris.

J'ai une classe qui contient une méthode moult fois surchargée:

Cette classe permet de gérer le comportement de l'appli en fonction du type
passé. L'appelant n'a pas à se soucier de quoi que ce soit.


En théorie ...

J'ai une deuxième classe qui contient la méthode suivante:

Classe 2 {

methode2 (Objet o) {
...
objetDeClasse1.methode1(o);
}

Le problème est que dans ce cas, c'est toujours la première méthode de
Classe1 (void methode1(Objet o)) qui est appelée, même lors d'un:
objetDeClasse2.methode2(new Integer(5));


C'est normal : dans ta methode2, tu as spécifié que tu souhaitais utiliser
un Object. Si tu veux conserver ton polymorphisme (et non surcharge, comme
tu le dis), il faudrait dans l'idéal que tu écrives un nombre suffisant de
methode2.
Bien évidement, cette solution n'est pas satisfaisante.

Une parade consiste à aller chercher la méthode adéquate avec un
getClass().getMethod(), mais cela me parait lourd et risqué: il peut y avoir
des erreurs dans le nom de la méthode, puis à l'exécution, et il faut de
suite gerer 3 exceptions... :(


Bon réflexe : si l'introspection est puissante, elle est rarement le silver
bullet escompté. Et elle retarde surtout au moment de l'exécution des
erreurs théoriquement visibles à la compilation.

N'y aurait-il pas moyen de faire un cast dynamique? Je n'ai pas trouvé
d'infos sur le sujet.


Non, il n'y a pas moyen.

Ma méthode2 s'écrirait alors dans le genre:

methode2 (Objet o) {
...
objetDeClasse1.methode1( (o.getClass()) o );
}


Je t'aurais bien proposé un petit double dispatch, mais il faut pour cela
que tu aies accès au code des différentes classes passées en paramtre, ce
qui ne semble pas être ton cas.

ce qui serait beaucoup plus simple à gérer, et plus propre à mon avis. Ou
alors dois-je revoir entièrement la structure de mon programme?


Comme disait captainplaf, c'est peut-être la meilleure solution, car le
grand nombre de redéfinitions de ta méthode n'est pas un indicateur de très
bonne qualité; Expliques donc un peu ce que tu souhaites faire.

Je cherche à
faire quelque chose de propre. Quelqu'un a une idée?

Merci d'avance pour votre aide.

Ced.



--
Nicolas Delsaux
"A lutter avec les mêmes armes que ton ennemi, tu deviendras comme lui."
Friedrich Nietzsch

Avatar
Laurent Bossavit
J'ai une classe qui contient une méthode moult fois surchargée:
void methode1(Objet o) {...}
void methode1(Integer o) {...}
void methode1(String o) {...}
void methode1(AutreObjet o) {...}


C'est demander beaucoup à Java.

Dans les langages objet, le concept de base est le polymorphisme: on a
seul un identifiant ("methode1" en l'occurrence) mais plusieurs
implémentations possibles, parmi lesquelles on choisit à l'exécution.

Mais attention - les langages objet classiques sont optimisés pour faire
ce choix en fonction du type du "receveur", c'est à dire l'objet sur
lequel on appelle la méthode. En d'autres termes, si tu avais 5 méthodes
"methode1" dans 5 classes différentes, pas de problème.

Là, tu voudrais qu'une sélection soit faite parmi 5 variantes de
"methode1" *dans la même classse*, et Java n'est pas prévu pour ça. Il y
a des langages qui le font bien, comme Cecil ou Dylan.

Si tu dois absolument faire marcher le truc ci-dessus, tu peux même
éventuellement faire appel à certaines extensions de Java: Nice,
MultiJava, JMMF, etc. (Google sur : "java multiple dispatch", "java
multi-methods".) Evidemment, dans ce cas tu ne fais plus du Java pur et
portable !

Il est possible et même probable qu'il existe une solution beaucoup plus
simple dans une conception propre, en Java tout bête.

Laurent
http://bossavit.com/

Avatar
vclassine
"Ced" wrote in message news:<bnnr9r$b9h$...
Salut a tous!

Les 2 premieres questions que j'ai envoyé sur ce newsgroup n'ont jamais eu
de réponse. J'espère être plus chanceux cette fois ci...
Aller t'en auras une cette fois...


J'ai une classe qui contient une méthode moult fois surchargée:

Classe1 {
void methode1(Objet o) {...}
void methode1(Integer o) {...}
void methode1(String o) {...}
void methode1(AutreObjet o) {...}
}

Cette classe permet de gérer le comportement de l'appli en fonction du type
passé. L'appelant n'a pas à se soucier de quoi que ce soit.

J'ai une deuxième classe qui contient la méthode suivante:

Classe 2 {

methode2 (Objet o) {
...
objetDeClasse1.methode1(o);
}

Le problème est que dans ce cas, c'est toujours la première méthode de
Classe1 (void methode1(Objet o)) qui est appelée, même lors d'un:
objetDeClasse2.methode2(new Integer(5));

Une parade consiste à aller chercher la méthode adéquate avec un
getClass().getMethod(), mais cela me parait lourd et risqué: il peut y avoir
des erreurs dans le nom de la méthode, puis à l'exécution, et il faut de
suite gerer 3 exceptions... :(
Lourd et risqué, effectivement (et plutôt moche de surcroit).


N'y aurait-il pas moyen de faire un cast dynamique? Je n'ai pas trouvé
d'infos sur le sujet.
Pas à ma connaissance, d'ailleurs à la limite si la résolution de cet

appel était dynamique java pourrait le faire implicitement (sous
réserve que je ne sois pas plus con que ce que je crois)...

Sinon tu peux faire un truc dans ce goût là.
if (o instanceof Integer)
cl1().methode1((Integer)o);
else if (o instanceof String)
cl1().methode1((String)o);
else
cl1().methode1(o);

Si tu opte pour ça autant écrire des noms différents, comme dans les
classe DataInputStream et DataOutputStream. Ce qui donne


if (o instanceof Integer)
cl1().methode1Integer((Integer)o);
else if (o instanceof String)
cl1().methode1String((String)o);
else
cl1().methode1(o);

Ou
alors dois-je revoir entièrement la structure de mon programme? Je cherche à
faire quelque chose de propre. Quelqu'un a une idée?
Effectivement il y a probablement une façon plus élégante de faire,

mais là il faudrait voir l'analyse du système complet... Mais une
indications pour la sélection automatique de la méthode en fonction du
type, c'est le polymorphisme.

Un peu comme System.out.println() ne sait pas comment se représente en
chaine chaque objet mais utilise la méthode toString() de chaque objet
sait comment se représenté en chaines (ou utilise la méthode par
défaut définie dans Object).

En l'occurence toString() st défini dans Object, mais ça peut se faire
avec une interface pour pourvoir traiter des classes sans ancêtre
commun (hormis Object).

A ce titre l'interface Comparable est un bon exemple...



Merci d'avance pour votre aide.
De rien en espérant t'avoir aider...


Ced.
Vincent.


Avatar
jerome moliere
<snip code>
Sinon tu peux faire un truc dans ce goût là.
if (o instanceof Integer)
cl1().methode1((Integer)o);
else if (o instanceof String)
cl1().methode1((String)o);
else
cl1().methode1(o);

Si tu opte pour ça autant écrire des noms différents, comme dans les
classe DataInputStream et DataOutputStream. Ce qui donne


if (o instanceof Integer)
cl1().methode1Integer((Integer)o);
else if (o instanceof String)
cl1().methode1String((String)o);
else
cl1().methode1(o);


arghllll , quelle horreur :)
jamais faire d'instanceof, cela denote une faiblesse de design evidente...
le pattern visitor est ton ami :)

Jerome

Avatar
Laurent Bossavit
le pattern visitor est ton ami :)


Difficile à utiliser quand on traite des String ou Integer, non ? Ces
classes sont déclarées "final", ce qui empêche de leur ajouter une
méthode accept().

Pour être complet notons que le pattern Visitor est une technique
d'implémentation du Double Dispatch, qui est lui-même un cas particulier
du multiple dispatch auquel je faisais allusion tout à l'heure.

Laurent
http://bossavit.com/

Avatar
vclassine
jerome moliere wrote in message news:...
<snip code honteux plein de instanceof>

arghllll , quelle horreur :)
jamais faire d'instanceof, cela denote une faiblesse de design evidente...
Euh, je ne dirais pas ça comme ça. L'instanceof à son utilité, même si

en l'occurence il dénote très probablement une faiblesse de design.

le pattern visitor est ton ami :)
SON ami


En fait j'ai écrit ça comme alternative au "cast dynamique" qu'il
cherche mais qui n'éxiste pas. Ou aussi comme alternative à un cast
static qu'il comptait, semble-t-il, gérer avec des
ClassCastException...

C'étatit donc une solution du "moins pire". Plus bas j'ai écrit qu'il
y aurait surement mieux à faire, mais avec le peu d'info dont on
dispose difficile de dire quoi...

Avatar
jerome moliere
Laurent Bossavit wrote:
le pattern visitor est ton ami :)



Difficile à utiliser quand on traite des String ou Integer, non ? Ces
classes sont déclarées "final", ce qui empêche de leur ajouter une
méthode accept().

certes mais on peut toujours imaginer une encapsulation..lourdingue

certes mais qui dit qu'il n'y a que ces types de donnees ?

Pour être complet notons que le pattern Visitor est une technique
d'implémentation du Double Dispatch, qui est lui-même un cas particulier
du multiple dispatch auquel je faisais allusion tout à l'heure.

exact...

mais j'avoue avoir un probleme avec le serveur NNTP de nerim qui me sort
des posts 3 jours après leur envoi:)


Jerome


Avatar
Ced
Hello all!

Tout d'abord, merci beaucoup pour vos nombreuses réponses. Désolé de ne pas
avoir répondu avant, j'ai été un peu occupé ces derniers jours...
Pour apporter quelques éclaircissements à ceux qui en ont demandé, je
souhaite créer une bibliothèque - servant à plusieurs programmes - qui me
permettent de sauvegarder/lire des objets dans une base de donnée. Le but
est d'avoir une couche qui encapsule tous les aspects techniques de l'acces
à la base de donnée.
L'idée était de créer un objet qui identifie la base de donnée, et qui
puisse offrir les méthodes:
sauveObjet(objet o)
lireObjet(objet o, critère c)

Cet objet saurait créer et exécuter les requetes apropriées en fonction de
l'objet passé en paramètre (d'où la surcharge). Une méthode "au dessus" de
toute les autres (celle qui prend le type Objet en paramètre) a le
comportement par défaut et renvoie une exception "je sais pas faire".
La classe que je souhaite créer doit aussi offrir la possibilité de
récuperer/sauver une liste d'objets. C'est ma méthode2. Elle prend Objet en
paramètre et appelle la sauvegarde/lecture unitaire autant que nécessaire
(certains d'entre vous vont etre etonnes de cette méthode, mais je passe sur
les détails).

Mon erreur est que je ramène au niveau de l'exécution le problème des
classes non gérées.
Je pense effectivement que le principe de l'interface sera le plus approprié
à mon besoin.

C'est bon, je suis parti pour tout refaire.... Ce que c'est, de se jeter
tête baissée dans le code... :p

Encore merci à tous, vos avis et conseils m'ont été précieux!

Ced.

"Vincent" a écrit dans le message de
news:
jerome moliere wrote in
message news:...

<snip code honteux plein de instanceof>

arghllll , quelle horreur :)
jamais faire d'instanceof, cela denote une faiblesse de design
evidente...


Euh, je ne dirais pas ça comme ça. L'instanceof à son utilité, même si
en l'occurence il dénote très probablement une faiblesse de design.

le pattern visitor est ton ami :)
SON ami


En fait j'ai écrit ça comme alternative au "cast dynamique" qu'il
cherche mais qui n'éxiste pas. Ou aussi comme alternative à un cast
static qu'il comptait, semble-t-il, gérer avec des
ClassCastException...

C'étatit donc une solution du "moins pire". Plus bas j'ai écrit qu'il
y aurait surement mieux à faire, mais avec le peu d'info dont on
dispose difficile de dire quoi...