Posez votre question Signaler

Classe abstraite et interface de java

wiam_ 163Messages postés 1 mars 2008Date d'inscription 14 mars 2012Dernière intervention - Dernière réponse le 1 juil. 2011 à 10:13
Bonsoir tt le monde ,
j'ai un peu du mal à comprendre les inerfaces et les classes abstraite en java j'ai lu pas mal du tutoriel et j'ai compris au niveau des methode (dans le classe fille on doit inpmlementer tout les methode de l'interface ........), mon probleme est je comprend pas à quoi ça sert l'interface et la classe abstraite ? si on devrait definir leur methodes dans les classes filles ? et quand on devrait choisir un interface ou une classe abstraite ?
je serais tres reconnaissante si vous pourrez me repondre .MERCI
Lire la suite 

Classe abstraite et interface de java »

30 réponses
Réponse
+13
moins plus
Bonjour messieur,
je sais que pour certain la "factorisation" semble inutile, mais ici, je vais vous expliquer ce à quoi ça sert. Il y a avant tout une grande nuance entre l'interface et la classe abstraite. L'interface permet de s'assurer que certaine classes filles auront sans aucun doute les méthodes définit dans celle-ci. La classes abstraite elle est un hybride entre une classe conventionnel et un interface. Elle offre une implémentation générique aux classes filles et également leur demande d'implémenter certaines choses pour lesquels la classe abstraite ne peut pas décider. Voici un exemple : Je veux réinventer Java2D et dessiner des formes a ma manière de A à Z. J'aurais donc une classe abstraite AbstraiteForme qui défini les méthodes de base telle que "setShader()", "setPosition()", etc. Par contre, la méthode dessiner() ne pourra pas être fournit par la classe abstraite. Donc cercle et carré auront a redéfinir comment elle voudront se déssiner. Les classes abstraite évite de réécrire 100 fois le meme bout de code dans chaque forme. Aussi, tu pourrais avoir une classe qui s'occupe de faire le draw. Avec une interface (ou une classe abstraite) ta pas besoin de savoir si tu va faire "dessiner()" sur un cercle ou un carré, tu sais juste que c'est une AbstraiteForme ou FormeIF et que ca ce dessine... Tu peux donc facilement ajouter ou retirer des forme dans ton système! :D Alors... la "factorisation"... c'est hyper puissant et ca sauve bcp de sous en dev (surtout coté maintenance!)
J'espere que c'est assez clair ;)
Marco la baraque- 1 sept. 2009 à 21:08
Bonsoir,
Merci de ton avis.
J'avoue avoir été un peu extrême en affirmant que "la factorisation ne sert à rien". J'entendais simplement :
"il ne faut pas créer de classe abstraite uniquement par souci de factorisation".

En effet, dans ce cas, on augmente le risque de bugs en voulant rendre générique du code similaire (certes si tu as 50 fois la même méthode, c'est qu'il y a un problème dans ta conception), et on crée des classes abstraites qui n'ont absolument aucun intérêt ni technique ni fonctionnel, car elles servent juste à centraliser du code.

Pour moi la notion d'héritage est bien plus riche que ça : on doit avant tout hériter d'un type, puis ensuite on hérite (et éventuellement défini ou redéfini) de ses méthodes. C'est d'ailleurs ce que tu expliques dans ton exemple avec les formes : tes objets étendent ta classe abstraite car ils sont similaire d'un point de vue comportement (un carré ou un rectangle c'est une figure 2D, donc elles étendent ta classe Figure2D), et non pas uniquement pour factoriser le code.

Si tu veux uniquement factoriser du code, tu peux utiliser un design pattern Wrapper, ce sera d'autant plus propre que tu ne "perdra" pas ton héritage (dans de nombreux langages objets l'héritage multiple n'existe pas, et étendre une classe abstraite uniquement pour factoriser du code fera que ta classe ne pourra plus étendre de classe par la suite, ce qui peut être gênant si tu souhaites étendre un type et un comportement par la suite).

Cordialement,
ASProd - 7 févr. 2010 à 12:39
Bonjour,

je sais que ce post date un peu maintenant, mais pour tous ceux qui tomberaient dessus par hasard comme moi, il peut être utile d'apporter encore quelques précisions.

Une interface, c'est avant tout un contrat, à savoir un ensemble de propriétés et méthodes que la classe DOIT implémenter.

Une classe abstraite, c'est avant tout une classe permettant de factoriser un ensemble de propriétés et de méthodes communes, voire même un constructeur commun.
C'est bien utile dans le cadre de l'écriture de plugins par exemple. Cela permet de définir des méthodes de construction et d'appel communes, permettant ainsi à l'application parente de ne connaitre que les points d'entrée de la classe abstraite.

Pour parler UML :
- L'interface permet de définir les Boundary (frontières) de la classe finale.
- La classe abstraite permet de définir les CU (Cas d'utilisation) simplifiées.
- La classe finale permet de définir les CU optimisées, prenant en compte les CU abstraites et concrètes.
Satelite01- 21 févr. 2011 à 21:32
Bonjour,

Je me permet de remonter ce poste... Car je suis, disons le, assez choqué par l'intervention de "Marco la baraque"!

Je reprend vos termes..
***
En effet, dans ce cas, on augmente le risque de bugs en voulant rendre générique du code similaire (certes si tu as 50 fois la même méthode, c'est qu'il y a un problème dans ta conception), et on crée des classes abstraites qui n'ont absolument aucun intérêt ni technique ni fonctionnel, car elles servent juste à centraliser du code.
***
Je donne un exemple simple d'implémentation, juste technique, de centralisation de code avec classes Abstraites...
J'ai besoin de définir des objets pour un projet personnel comme tel : Les données ci dessous sont à titre d'exemple...

Objet A : variables : String name, String phoneNumber
Objet B : variables : String name, String insuranceNumber
Objet C : variables : String name, ImageIcon image, String productId
Objet D variables : String name, ImageIcon image, String comment

Cas avec factorisation via classes Abstraites ca donne :
Toutes les classes ci dessous ont juste les getter et setter pour les variables qu'elles portent en public
Abstract class AbstractBeanWithName : String name
Abstract class AbstractBeanWithImage extends AbstractBeanWithName : ImageIcon image
BeanWithPhoneNumber extends AbstractBeanWithName
BeanWithInsuranceNumber extends AbstractBeanWithName
BeanWithProductIdNumber extends AbstractBeanWithImage
BeanWithCommentNumber extends AbstractBeanWithImage

- Les variables ont le même nom partout, uniformité...
- Si je veux savoir quels objets ont une image, je recherche les références à AbstractBeanWithImage (gain de temps énorme)
- Gain de place énorme.. si on connait son architecture, on sait de suite quelles variables sont héritées
- Maintenabilité parfaite..., besoin d'une vérification de saisie sur une variable... je peux la mettre au niveau du setter, exemple bidon mais probant, une seule méthode à retoucher
-- j'ai besoin un jour d'un objet avec juste un nom, je retire Abstract de ma classe AbstractBeanWithName qui devient BeanWithName... , même chose si un jour besoin d'un objet avec nom et image... AbstractBeanWithImage devient BeanWithImage
- Si un traitement est particulier à l'un des objets... par exemple le nom sur BeanWithPhoneNumber et qu'il existe déjà un traitement sur ce setter que tous les autres objets utilisent, l'override du setter est possible... Cas super rare si la spec est bien faite au départ... l'analyse, mais une seule méthode à créer...

Cas sans facto :

Object A : variables : String name, String phoneNumber
Object B : variables : String name, String insuranceNumber
Object C : variables : String name, ImageIcon image, String productId
Object D variables : String name, ImageIcon image, String comment

- Les variables peuvent finir avec des noms différents.. ex : nom, name, data_name (ce qui arrive souvent, si peu de factorisation du code... et ca devient totalement illisible)
- Je dois ouvrir toutes les classes pour savoir lesquelles portent une image... puisque chaque classe pouvant être codée par des dev différents, les noms des variables peuvent changer...
- Classe 4 fois plus grande que dans l'autre cas... donc scrolling... et il faut ouvrir tout pour savoir qui porte quel type de variable, méthodes, même si identique (name) (image)
- Maintenabilité faible, si une modification est à reporter partout, cas de la vérification de saisie sur un setter, je dois parcourir toutes les classes et faire un copier collé bête et méchant (perte de temps, risque d'oubli, sans compter le noms des méthodes et des variables qui peuvent changer) setNom, setName etc....
-- j'ai besoin un jour d'un objet avec juste un nom, je rajoute une classe... risque de changer de nom de variable... etc etc , même chose si un jour besoin d'un objet avec nom et image...
- Si un traitement est particulier à l'un des objets... je l'implémente dans son coin

Bref, d'expérience, sur les projets non factorisés... sans aller dans l'extrême que j'ai exposé... Qui reste cependant totalement valable et probant, puisque là, c'était juste une factorisation purement technique... On obtient :

- Des classes codées par des devs différents, qui font la même chose... car manque de connaissance de l'architecture du projet
- Des variables à l'utilité identique... String nom, qui changent name, nom, data_name, illisible, impossible à facilement retrouver dans le code, à part tout parcourir
- Problème de performance, car certaines méthodes ayant le même but, la même fonction, vont changer de nom, d'algorithme, impossible à retrouver... parfois on fait une correction dans un coin et oh zut, un abrutis à fait la même chose avec un autre nom, seulement, je dois me taper 40 lignes de code, pour bien vérifier que c'est la même

La factorisation est l'a-panache de la perfection en programmation...
Gain de temps, Maintenabilité, lisibilité --> GML lol

***
Pour moi la notion d'héritage est bien plus riche que ça : on doit avant tout hériter d'un type, puis ensuite on hérite (et éventuellement défini ou redéfini) de ses méthodes. C'est d'ailleurs ce que tu expliques dans ton exemple avec les formes : tes objets étendent ta classe abstraite car ils sont similaire d'un point de vue comportement (un carré ou un rectangle c'est une figure 2D, donc elles étendent ta classe Figure2D), et non pas uniquement pour factoriser le code.
***

Vrai et Faux...
Vrai, si vous instanciez Figure2D... uniquement! et donc que celle ci ait une raison de l'être!
Faux, dans le sens ou... une classe abstraite trouve son utilité quand vous avez des objets dont l'implémentation de certaines méthodes différent... dessiner() comme l'a si bien exposé "misterETS", mais que des méthodes et/ou variables sont communes static ou pas...
Si Figure2D, n'est qu'un agrégat de méthodes et variables communes aux objet à dessiner en 2d, mais que chacun d'eux se dessine différemment, Figure2D n'a aucune raison d'être instanciée en temps que tel, puisqu'elle ne porte que la description de la méthode dessiner... Figure2D ne dessinant rien en soit même, on la met en Abstract... Logique des plus basique!

CQFD : Une classe abstraite est donc par nature une classe permettant de factoriser du code et de permettre tout de même une divergence de comportement de ses enfants... C'est donc un outil très puissant, mais qu'il faut savoir manier... Ce qui est encore appuyé par le fait que les variables définies dans une classe abstraite peuvent être public, protected, private en opposition à une interface dont les variables ne peuvent être que public...
Ainsi que par le pattern Template...
Une classe abstraite est aussi et comme son nom l'indique, utile pour abstraire un code client des spécificités des classes filles de cette classe abstraite...
Si une méthode reçoit en argument une classe concrète (instanciable) dans un code "client", toute modification des particularités de cette classe seront à prendre en compte dans le code "client", ainsi que si il y a ajout d'une classe concrète de la même famille...
Si maintenant celle ci reçoit en argument la Classe abstraite mère d'une famille de classes concrètes... le code client s'abstrait de leur particularités, sera plus facilement maintenable et la modification, création de classes concrètes de cette même famille (héritant la même classe abstraite passé ici en argument) ne demandera retouche du code client, que si, il y a ajout de nouvelle fonctionnalités (méthodes) utiles... dans son cas ;) (Pattern Abstract Factory)

****
Si tu veux uniquement factoriser du code, tu peux utiliser un design pattern Wrapper, ce sera d'autant plus propre que tu ne "perdra" pas ton héritage (dans de nombreux langages objets l'héritage multiple n'existe pas, et étendre une classe abstraite uniquement pour factoriser du code fera que ta classe ne pourra plus étendre de classe par la suite, ce qui peut être gênant si tu souhaites étendre un type et un comportement par la suite).
****

Le design pattern Wrapper est très proche de l'adapter et au final est plus proche de la spécialisation que de l'héritage, donc à l'opposer fondamentalement de la factorisation de code...
De plus, je rappel que les classes abstraites peuvent hériter d'autre classes.... Votre explication ne fait que malheureusement souligner votre manque de connaissances en la matière et risque justement d'induire en erreur des développeurs et de provoquer une faible maintenabilité, ainsi qu'un nombre de classes exponentielles... par rapport au besoin!

En espérant éclaircir le sujet pour les futurs lecteurs, a bon entendeur ;)
Ajouter un commentaire
Réponse
+5
moins plus
Bonsoir,
Pour compléter ce que dit Walkhess, l'utilisation d'interfaces et de classes abstraites, ça a deux avantages.
- la factorisation de code. Selon certains, la factorisation est l'un des avantages de la programmation orientée objet, selon d'autres (et j'adhère à ce mouvement de pensée), la factorisation ça ne sert à rien, sauf parfois à concevoir de mauvais programme par souci de "sur-factorisation".
La factorisation, ça consiste à écrire des méthodes dans les classes, de manière à pouvoir les réutiliser sans les retaper dans les classes filles. C'est ce qui est utilisé lorsque tu implémentes des méthodes dans ta classe abstraite : si toutes les classes filles ont le même comportement pour cette méthode, alors elle doit être implémentée une et une seule fois dans la classe abstraite
- l'abstraction (le polymorphisme). C'est la manière d'utiliser une référence vers une interface (qui définit une série de méthodes), et d'utiliser une implémentation concrète, mais sans la connaître.
Par exemple, quand tu vas utiliser une liste (interface java.util.List), tu ne vas pas connaître quelle implémentation tu vas utiliser. Tu vas par contre savoir que tu peux insérer un élément à un endroit, en supprimer un, connaître la taille...
Et donc dans ton code, tu vas utiliser une référence vers une List.
Ensuite, tu vas utiliser réellement une implémentation de cette interface, mais d'un point de vue utilisation, tu ne sauras pas ce que c'est. Que ce soit une LinkedList (suppression et insertion en O(n) par exemple), ou une ArrayList(en temps constant pour ces méthodes), ça ne t'intéresse que lorsque tu compares les performances lors de l'implémentation initiale de ton ensemble. Une fois que c'est fait, tu fais abstraction de cet aspect "bas-niveau" pour te concentrer uniquement sur l'utilisation de ta liste, et donc tu passes par ton interface.

En espérant avoir été un peu plus loin, sans avoir été trop confus...

Cordialement
Ajouter un commentaire
Réponse
+4
moins plus
voilà ce n'est pas aussi compliquer :

une classe abstraite est une classe dont les méthode sont abstrait c.à.d lorsque tu déclare une méthode abstract automatiquement tu doit définir la classe " abstract" et elle est utiliser généralement quand d'autre classes vont hériter de cette classe et ils ont la même méthode que la classe mére donc ont l'écrit pour ne pas répeter les mêmes méthodes chaque fois dans ces classes.

pour les interfaces sont utilisés quand d'autres classes qui vont avoir les même méthodes ont les définies dans une interfaces et puis l'implémenter ultérieurement même si tu n'a pas besoin d'une méthode dans l'interface tu doit l'implémenter par exemple tu peut simplement écrire le nom de la méthode puis ouvrir et fermer l'accolade(je crois que s'écrit comme ça non accolade) comme ça : public void méthode(){}. Engénéral il n'y a pas une grande différence entre interface et classe abstraire ; une interface est un cas paticulier d'une classe abstarite .

bonne travail
olfa - 12 déc. 2010 à 17:38
je veux un programme en java avec une classe abstraite
sahar - 10 janv. 2011 à 11:45
olfa on passe pas les commandes par ici, et puis on dit "svp" ^^
Ajouter un commentaire
Réponse
+0
moins plus
merci à vous les deux c'est plus clair maintenant
Ajouter un commentaire
Réponse
+0
moins plus
bonjour,

Moi je voulais comprendre d abord quant est ce qu'on utilise des classes abstraites ?

Merci
KX- 17 janv. 2011 à 12:40
Les classes sont abstraites quand elles ne sont pas directement instantiables.
Par exemple si tu représentes le règne animal, la classe Animal sera abstraite, de même que ses classes filles Mammifère, Oiseau, Reptile...
En effet il y certaines caractéristiques qui ne sont pas connues et qui ne peuvent pas être implémentées (par exemple le nombre de pattes qui varie selon l'espèce)
Par contre des classes finales comme Chat, Aigle, Serpent... pourront être totalement implémentées puis éventuellement spécifiées (ChatPersan, AigleRoyal, Vipere...)
soum - 18 janv. 2011 à 14:26
Merci beaucoup pour la réponse.
soum - 25 janv. 2011 à 16:09
Vu que je suis débutante en programmation java, j'aimerai avoir une idée pour concevoir et implémenter une petite application java afin de m'entraîner sur java OO.
Merci
Ajouter un commentaire
Réponse
+0
moins plus
Moi je suis capable de faire des interfaces sans que ce sois une interface dans le sens propre du terme. Une interface ces une classe abstraite dont toute les méthodes sont abstraites. Très important à savoir car ce n'est pas tout les languages de programmation qui on la notion d'interface(ie. C++) mais simplement la notion d'heritage multiple.
saturnxv1 - 29 juin 2011 à 18:05
Moi, j'aurais bien vu une simple matrice pour le graphe... La case (i,j) représentant soit le poids de la liaison (i,j), soit un booléen disant si cette liaison existe.
Trier un arbre n'a effectivement aucun sens, mais puisque tu dis qu'une collection n'a pas forcément besoin d'être ordonnée (donc triable)...
KX- 29 juin 2011 à 19:52
1) la représentation matricielle pour un graphe c'est pas top
2) je ne vois pas en quoi ce serait une Collection : quels serait les éléments contenus ?
3) on s'éloigne du problème, non ?
saturnxv1 - 1 juil. 2011 à 10:13
1/ Ça dépend de l'usage que l'on en fait, il y a tellement d'applications différentes...
2/ Là, comme ça, j'aurais dit les feuilles de l'arbre.
3/ Oui, c'est vrai, j'essayais juste de trouver un exemple, mais on est un peu parti à l'ouest. En tout cas, merci pour tes réponses.
Ajouter un commentaire
Réponse
+0
moins plus
comment je fais pour en plus être sur el mailing list de ce forum ?
KX- 29 juin 2011 à 14:47
Dans les mails que tu reçois tu as un lien "Arrêter les envois de mails concernant cette discussion "
Ajouter un commentaire
Ce document intitulé « classe abstraite et interface de java » issu de CommentCaMarche (www.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.
Dossier à la une
Passage au tout numérique : quel coût pour les particuliers ?