Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Comment coder un enum via une classe « normale »

59 réponses
Avatar
Francois
Bonjour à tous,

Ma question n'a pas un grand intérêt pratique, c'est juste pour
comprendre les enum. En fait, je comprends bien l'utilité des enum et la
façon dont on s'en sert. Mais, si j'ai bien compris, le mot clé "enum" a
été créé dans la version 1.5 de Java pour avoir un type énuméré en deux
coup de cuillère à pot, sachant qu'avant la version 1.5 il fallait coder
soi-même sa propre classe donnant le type énuméré souhaité.

Justement, on codait comment en version 1.4 (ou antérieure) ? Par
exemple, comment avec une classe « normale » peut-on coder un équivalent
de cet exemple très simple de type enum :

public enum Etat {
DEHORS,
DEDANS
}

Merci d'avance.

--
François Lafont

10 réponses

1 2 3 4 5
Avatar
Francois
Wykaaa a écrit :

J'ai l'impression que tu peux apprendre des choses (même si elles ne
sont pas vraiment en rapport avec ton post initial, ce dont je te pris
de m'excuser...)



Non, non, il n'y a pas de problème, tout ceci m'intéresse.


Vous n'êtes pas le premier à me dire cela, loin de là. J'avoue que
pour moi, ça reste floue cette histoire d'éviter les switch.



Qu'est-ce qui est flou pour toi ?



Par "flou", je voulais dire en fait que je n'ai jamais eu l'expérience
réelle et palpable des inconvénients du switch. Mais cela vient du fait
que, étant un simple programmeur du dimanche, mes petits codes n'ont pas
un volume assez important pour rendre palpable cette vérité selon
laquelle le switch c'est pas bien en objet. C'est toujours un problème
d'échelle. Sur un code de 50 lignes, dire que le switch c'est pas bien,
c'est jamais très frappant.

Remplacer les switch par le polymorphisme est la façon la plus naturelle
d'introduire l'héritage dans une programmation. Il faut que ceci ait été
prévu dès la conception car on ne trafique jamais le code impunément...



Je retiens l'idée : "pas de switch en objet, on utilise le polymorphisme
à la place". Ceci étant, Samuel avait sur ce point des reproches que
hélas je n'ai pas trop saisis (histoire de code livré/pas livré,
enrichissement de classe par le bas, tout ça...)

Mais quand tu écris switch (monEnum)
{
case c1 : ...
case c2 : ...
other : ...
}
que fais-tu, sinon définir un traitement sur ton enum ?



C'est vrai. On associe des données avec des traitements.

et tu ne va pas, pour un enum donné, définir des centaines de traitement
(de switch donc) différents sinon c'est qu'il y a un vrai problème de
conception...



Ok, le message est bien passé. Mais il y a juste une chose. Faire du
enum et du switch, c'est associer données et traitements, donc il faut
repenser la chose en objets via le polymorphisme. Mais alors dans ce cas
pourquoi s'embêter avec des enum. Dans ce cas, on fait des vraies
classes et on laisse tomber le enum. En fait, dans votre logique, j'ai
l'impression que les enum n'apportent rien et qu'on pourrait s'en passer
largement puisqu'on en arrive à faire finalement des vraies classes avec
l'héritage et compagnie. À la limite, dans votre logique, vous me diriez
que vous ne voulez pas entendre parler des enum, je trouverais ça plus
cohérent. Remarquez, c'est peut-être le cas d'ailleurs, puisque dans
l'exemple d'implémentation de l'enum Etat, vous n'avez justement pas
utilisé d'enum.



--
François Lafont
Avatar
Adrien Grand
Francois a écrit :
Mais dans les "switch/case", on a le droit de mettre des enum justement,
non ? En tout cas, chez moi, ceci compile sans problème :



Je répondais à ta question initiale "Comment aurait-on fait avant Java 5 ?".

--
jpountz
Avatar
Adrien Grand
Francois a écrit :
Mais dans les "switch/case", on a le droit de mettre des enum justement,
non ? En tout cas, chez moi, ceci compile sans problème :



Je répondais à ta question initiale "Comment aurait-on fait avant Java 5 ?".

--
jpountz
Avatar
Adrien Grand
Wykaaa a écrit :
Rappelez-vous ceci :
La chasse au switch est à la programmation objet ce que la chasse au
goto est à la programmation structurée !



http://xkcd.com/292/

--
jpountz :-)
Avatar
Wykaaa
Francois a écrit :
Wykaaa a écrit :

J'ai l'impression que tu peux apprendre des choses (même si elles ne
sont pas vraiment en rapport avec ton post initial, ce dont je te pris
de m'excuser...)



Non, non, il n'y a pas de problème, tout ceci m'intéresse.


Vous n'êtes pas le premier à me dire cela, loin de là. J'avoue que
pour moi, ça reste floue cette histoire d'éviter les switch.



Qu'est-ce qui est flou pour toi ?



Par "flou", je voulais dire en fait que je n'ai jamais eu l'expérience
réelle et palpable des inconvénients du switch. Mais cela vient du fait
que, étant un simple programmeur du dimanche, mes petits codes n'ont pas
un volume assez important pour rendre palpable cette vérité selon
laquelle le switch c'est pas bien en objet. C'est toujours un problème
d'échelle. Sur un code de 50 lignes, dire que le switch c'est pas bien,
c'est jamais très frappant.



Ca c'est sûr que pour 50 lignes de code, moi aussi je vais faire un
switch :-)

Remplacer les switch par le polymorphisme est la façon la plus
naturelle d'introduire l'héritage dans une programmation. Il faut que
ceci ait été prévu dès la conception car on ne trafique jamais le code
impunément...



Je retiens l'idée : "pas de switch en objet, on utilise le polymorphisme
à la place". Ceci étant, Samuel avait sur ce point des reproches que
hélas je n'ai pas trop saisis (histoire de code livré/pas livré,
enrichissement de classe par le bas, tout ça...)



Tout ce dont parle Samuel est très important. Ça concerne ce que, dans
le jargon, on appelle le "packaging", c'est-à-dire comment on organise
le code. Par exemple certains préconisent de mettre une classe abstraite
seule dans un fichier, ses sous-classes étant dans le même package (au
sens de Java) mais dans un fichier différent.
C'est une question d'organisation et Java est plus souple que C++ de ce
point de vue car il a la notion de package alors qu'en C++, un module
est un fichier.

Mais quand tu écris switch (monEnum)
{
case c1 : ...
case c2 : ...
other : ...
}
que fais-tu, sinon définir un traitement sur ton enum ?



C'est vrai. On associe des données avec des traitements.



Des données sans traitement sont inutiles, que les données soient des
enum ou des abstractions plus complexes. Un enum est une abstraction
comme une autre, avec des traitements associés qui sont liés à ce que
représente cette abstraction donc la classe (qui est la façon de décrire
une abstraction dans la plupart des langages objets les plus utilisés)
est bien la façon la plus adéquate de les représenter.

et tu ne va pas, pour un enum donné, définir des centaines de
traitement (de switch donc) différents sinon c'est qu'il y a un vrai
problème de conception...



Ok, le message est bien passé. Mais il y a juste une chose. Faire du
enum et du switch, c'est associer données et traitements, donc il faut
repenser la chose en objets via le polymorphisme. Mais alors dans ce cas
pourquoi s'embêter avec des enum. Dans ce cas, on fait des vraies
classes et on laisse tomber le enum. En fait, dans votre logique, j'ai
l'impression que les enum n'apportent rien et qu'on pourrait s'en passer
largement puisqu'on en arrive à faire finalement des vraies classes avec
l'héritage et compagnie. À la limite, dans votre logique, vous me diriez
que vous ne voulez pas entendre parler des enum, je trouverais ça plus
cohérent. Remarquez, c'est peut-être le cas d'ailleurs, puisque dans
l'exemple d'implémentation de l'enum Etat, vous n'avez justement pas
utilisé d'enum.



Tu as bien compris. En objet, pour moi, les enum ne sont pas nécessaires
car ils "poussent" à l'utilisation de switch ce qui ne facilite pas la
maintenance. L'"aiguillage" doit se faire via le polymorphisme qui est
le mécanisme naturel dans les langages objet.
Avatar
Adrien Grand
Salut,

Francois a écrit :
Par "flou", je voulais dire en fait que je n'ai jamais eu l'expérience
réelle et palpable des inconvénients du switch. Mais cela vient du fait
que, étant un simple programmeur du dimanche, mes petits codes n'ont pas
un volume assez important pour rendre palpable cette vérité selon
laquelle le switch c'est pas bien en objet.



Ça n'est pas une vérité absolue. Pour certains problèmes, ça n'a juste
pas de sens d'utiliser le polymorphisme. Imagine que tu aies une classe
Conducteur et une enum FeuTricolore qui peut prendre les valeurs VERT,
ORANGE et ROUGE. Si tu souhaites associer des comportements différents à
ton conducteur selon la couleur du feu, il faut justement utiliser un
switch et pas le polymorphisme.

Il est important que tes APIs restent logiques, et vouloir utiliser le
polymorphisme t'obligerait à ajouter des méthodes à ton feu qui prennent
un conducteur en argument. Or la classe FeuTricolore n'a pas à savoir
qu'il existe une classe Conducteur (C'est au conducteur de se préoccuper
du feu, pas le contraire). Le code qui associe la réaction du conducteur
à la couleur du feu devrait donc logiquement se trouver dans la classe
Conducteur.

Mais il y a juste une chose. Faire du
enum et du switch, c'est associer données et traitements, donc il faut
repenser la chose en objets via le polymorphisme. Mais alors dans ce cas
pourquoi s'embêter avec des enum. Dans ce cas, on fait des vraies
classes et on laisse tomber le enum. En fait, dans votre logique, j'ai
l'impression que les enum n'apportent rien et qu'on pourrait s'en passer
largement puisqu'on en arrive à faire finalement des vraies classes avec
l'héritage et compagnie. À la limite, dans votre logique, vous me diriez
que vous ne voulez pas entendre parler des enum, je trouverais ça plus
cohérent. Remarquez, c'est peut-être le cas d'ailleurs, puisque dans
l'exemple d'implémentation de l'enum Etat, vous n'avez justement pas
utilisé d'enum.



Il faut utiliser des enum quand tu cherches à décrire quelque chose qui
ne peut prendre qu'un nombre fini et connu de valeurs, comme l'état
physique d'un matériau (solide, liquide, gazeux), la couleur d'un feu
tricolore, ou les jours de la semaine. (Utiliser le polymorphisme pour
ce genre de chose n'a pas de sens.)

La documentation de Sun donne des bons exemples d'utilisation des enums :
http://java.sun.com/docs/books/tutorial/java/javaOO/enum.html
Avatar
Samuel Devulder
Francois a écrit :

Vous n'êtes pas le premier à me dire cela, loin de là. J'avoue que pour
moi, ça reste floue cette histoire d'éviter les switch.




Moi aussi. Je ne comprends pas trop les puristes qui mettent de l'objet
partout, surtout où il n'en faudrait pas et produisent des systèmes:
- lents et gourmand en mémoire: les objets ont un coût non négligeable
par rapport aux types de base
- non évolutifs parce que le traitement n'est plus localisé à un endroit
facilement modifiable mais dispersé dans 36 classes intiment lié aux
choix de l'algo implémenté. Changer d'algo revient à toucher ces 36
classes, bref à faire un redesign complet (et alors que cela n'aurait pu
n'affecter qu'une seule classe: celle effectuant le traitement.

Bref: les data se dispersent dans l'arbre d'agrégation et c'est très
bien car elles sont utiles à beaucoup, mais faire la même chose
systématiquement pour le traitement peut être mauvais si la granularité
n'est pas bonne. Ainsi choisir de faire une méthode par switch est un
mauvais choix à mon avis.

Un truc simple pour savoir si le découpage est le bon est de regarder si
les méthodes-switch ne sont appelées que depuis un seul point (ce qui
est assez logique vu qu'elles effectue un traitement qui aurait du être
fait par une autre classe). Si c'est le cas, il faudrait voir si le
traitement n'est pas trop spécifique au point d'appel et ne devrait pas
être publié par la classe-enum mais plutôt déplacé à l'endroit où on en
a besoin.
Avatar
Francois
Wykaaa a écrit :

En objet, pour moi, les enum ne sont pas nécessaires
car ils "poussent" à l'utilisation de switch ce qui ne facilite pas la
maintenance. L'"aiguillage" doit se faire via le polymorphisme qui est
le mécanisme naturel dans les langages objet.



Ok, j'ai bien compris votre point de vue.

Merci bien.


--
François Lafont
Avatar
Samuel Devulder
Wykaaa a écrit :

Mais quand tu écris switch (monEnum)
{
case c1 : ...
case c2 : ...
other : ...
}
que fais-tu, sinon définir un traitement sur ton enum ?
et tu ne va pas, pour un enum donné, définir des centaines de traitement
(de switch donc) différents sinon c'est qu'il y a un vrai problème de
conception...



Je m'inscrit en faux! L'enum peut avoir effectivement des centaines de
traitements. Imagines l'enum représentant les jours de la semaines. Il y
a pleins de traitements différents qui seront fait dans une (ou des)
applis en fonction de sa valeur.

Ce qui me gêne aussi dans l'approche de Wykaa c'est que le système est
fermé. La bibliothèque avec les jours de la semaine fourni sous la forme
d'un jar ne pourra pas être étendue avec de nouveaux traitement.

Cette approche ne fonctionne que si tout est coulé dans le béton et
qu'on ne touche plus rien après. C'est pas idéal.

Et bonjour, pour modifier les centaines de switch, si tu ajoute une
valeur à ton enum ;-)




Remarque que beaucoup font comme ça et que c'est pour ça que les
programmes sont difficilement maintenables et évolutifs et qu'il faut
les jeter au bout de 4 ou 5 versions...




J'ai le même argument dans l'autre sens :) Il est des progs (plusieurs
milions) avec switch qui sont super maintenables et évolutifs aussi.

sam.
Avatar
Francois
Adrien Grand a écrit :

Mais dans les "switch/case", on a le droit de mettre des enum justement,
non ? En tout cas, chez moi, ceci compile sans problème :



Je répondais à ta question initiale "Comment aurait-on fait avant Java 5 ?".



Ah pardon, au temps pour moi. :-)


--
François Lafont
1 2 3 4 5