Je voulais savoir d'après vous c'est quoi exactement l'interet des interfaces en java, car perso, je trouve qu'elles sont inutiles, pourquoi ne pas implémenter directement dans les classes concretes sans passer par des interfaces???
Je voulais savoir d'après vous c'est quoi exactement l'interet des interfaces en java, car perso, je trouve qu'elles sont inutiles, pourquoi ne pas implémenter directement dans les classes concretes sans passer par des interfaces???
Et l'intérêt de la fonction recherche ? Inutile aussi ?
Je crois que ta question risque de provoquer des arrets cardiaques à pas mal de personne ici . Une interface permet de décrire un comprotement particulier. C'est un moyen de typer les objets par leur competences (les méthodes qu'ils savent executer) plutot que par leur classe.
De plus, utiliser des interfaces te permet d'introduire beaucoup de souplesses dans le developpement de ton application. Imagine que pour un algorithme tu necessite de calculer la distance entre deux points (algorithme A* par exemple). Il existe différent types de distances (euclidienne, de Manhattan, diagonale ...). Si tu veux que ton application soit modulaire, tu as tout interet a manipuler une interface qui contient une methode calculerDistance plutot qu'une implementation directement. Je te conseille un ouvrage interessant qui aborde notamment ce sujet et plus generalement la "bonne" facon de concevoir une appli orientée objet : "design patten : la tete la premiere" chez oreilly
c'est quoi le rapport ? pour toi c quoi l'interet ?Envoyé par nicØB
Il n'y a pas possibilité d'héritage multiple en java, donc on passe par les interfaces. Par exemple, il suffit de regarder dans l'api standard. Si tu prends l'interface List, il y a plusieurs classes qui implémente cette interface, de leur propre manière. Et si tu dois manipuler des lists de toute sorte, tu n'aura qu'à manipuler l'interface.
Les interfaces sont utilisées dans les pattern de type Factory ou pour l'injection de dépendance.
Les interfaces sont des contrats que les classes qui les implémentent doivent respecter, même si le développeur peut les implémenter comme il veut. Il manque peut-être un mécanisme de contrôle type programmation par contrats.
Une interface permet beaucoup!!
Une interface, c'est un contrat: une classe qui implémente "Comparable" permet de comparer plusieurs instances de cette classes entre elles afin de définir laquelle est supérieure ou inférieure.
Implémenter une interface, ça revient à déclarer "cette classe est capable de faire ceci".
C'est en utilisant les interfaces que l'on peut "simuler" un héritage multiple (la terminologie que j'emploie n'est pas tout à fait exacte): une classe peut implémenter Comparable, Cloneable, Iterable, et plein d'autres interfaces. Cela permet de "greffer" des fonctionnalités sur des classes.
Cela permet aussi d'utiliser des classes sans se préoccuper de leur type réel et de leur implémentation, afin de pouvoir tout modifier plus facilement par la suite.
L'exemple typique des listes:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 ArrayList a = new ArrayList(); // Mauvais, car "ArrayList" est référencé directement, alors qu'il ne s'agit que d'une implémentation de Collection Collection c = new ArrayList(); // Bon, car on peut facilement modifier "new ArrayList()" par "new HashTable()" ou "new TreeSet()", sans que cela modifie le reste du programme
Les interfaces sont sans doute l'une des meilleure trouvail de Java!
Une interface decrit le contrat que doit respecter une implementation. Exemple concret :
Si tu prends le moteur Essence ou Diesel, la classe devra respecter (implementer) au MINIMUM ces 3 méthodes. Bien-sûr le corps des méthodes est completement libre (le demarrage d'un moteur essence ne se faisant pas de la même manière qu'un moteur essence).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 public interface Moteur { void demarrer(); void arreter(); void pause(); }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 public abstract class Moteur { public abstract void demarrer(); public abstract void arreter(); public abstract void pause(); }
Dans certains cas je préfère un abstract. J'ai parfois du mal à choisir entre interface et classe abstraite. L'avantage d'une interface c'est qu'une classe peut hériter de plusieurs interface alors qu'une classe ne peut étendre qu'une seule classe abstraite ...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 public class MoteurEssence extends Moteur { }
Tout dépend du contexte ...
Envoyé par sleepy2002
Ce n'est pas la première fois que quelqu'un pose cette question.Envoyé par gloglo
Un autre intérêt pour ma part c'est lorsque l'on utilise Spring (ou autre lib permettant de faire de l'injection de dépendances).
Celon le contexte, on charge l'implémentation que l'on veut.
dans ce cas je ne vois pas l'utilité de la classe abstraite étant donné que tu ne définie aucune méthode. Une interface serait donc mieux adapté.Envoyé par pgervaise
L'avantage d'une interface c'est quand tu veux un type générique sans avoir à te préoccuper de la manière dont seront réaliser les choses.
Suppose qu'on te demande de faire une application chargé de gérer l'envoie de message à des personnes d'un listing. Sauf que les moyens d'expédition du message sont différents. Certaine personnes le voudraont par mail, d'autres par courrier, d'autre par mail (et j'en passe).
Sans interface, tu te retrouve à faire :
avec toute les déclarations et définitions qui vont avec (soit trois objets minimum).
Code : Sélectionner tout - Visualiser dans une fenêtre à part Sms.envoie(message); ou Mail.envoie(message); ou Courrier.envoie(message)
Avec l'interface tu pourrais faire :
avec seulement Envoyeur qui définit Sms, Mail ou Courier en fonction du clients.
Code : Sélectionner tout - Visualiser dans une fenêtre à part Envoyeur.envoie(message)
Demain, on invente un nouveau moyen de communication (holovision par exemple). Dans le premier cas tu dois tout refaire pour ce nouveau moyen, dans le second tu implément Envoyeur tu ajoute une condition et c'est fini.
Je me suis un peu laisser aller désolé
Bonjour à toutes et à tous,
Sans vouloir polémiquer, mais pour avoir les idées plus claires sur la différence entre classe abstraite et interface, quelqu'un pourrait-il écrire un petit programme basé sur l'exemple précédent (des destinataires, des moyens d'expédition) en utilisant d'un côté des classes abstraites et de l'autre des interfaces.
Pour moi :
- avec des interfaces : il faut créer autant d'interfaces qu'il y a de moyens d'expédition, puis créer une classe implémentant toutes ces interfaces. Si on ajoute un moyen d'expédition, il faut créer une nouvelle interface, l'implémenter dans la classe utilisatrice et faire un nouveau "switch" dans cette classe.
- avec des classes abstraites, il faut créer autant de classes à partir de la classe abstraite qu'il y a de moyens d'expédition, puis une classe qui exploite chacune des classes précédemment créées. Si on ajoute un moyen d'expédition, il faut créer une nouvelle classe issue de la classe abstraite et ajouter un "switch" dans la classe utilisatrice.
Voilà ce que j'ai compris, mais je suis peut-être complètement à côté de la plaque. C'est pourquoi un petit programme valant mieux que de longs discours ...
Au niveau applicatif, le listing comprend bien des couples "destinataire/moyen d'expédition" qui vont exploiter les ressources définies ci-dessus.
Merci de votre aide.
Pierre.
Hello,
il n'y a pas vraiment de solution purement "interface" ou purement "classe abstraite"
La meilleure logique serait de partir d'une interface, de l'implémenter dans une classe abstraite, puis de définir des classes concrètes à partir de la classe abstraite.
De toute façon, au final, le code doit se trouver dans des classes... L'utilisation d'interfaces ne fait que modifier le type de référence.
Une implémentation de l'exemple ci-dessus pourrait être comme cela:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 // Déclare l'interface d'un envoyeur interface Sender { void setRecipient(String s); void send(String msg); } // Ici, je défini l'implémentation standard de tous les "Sender", par ex. "setRecipient(String)" qui permet d'affecter un destinataire // Les classes abstraites contiennent généralement des implémentations standards pouvant être modifiés par les sous-classes abstract class AbstractSender implements Sender { protected String recipient; public void setRecipient(String s) {recipient = s;} public void toString(){ return "Sender de classe "+getClass().getSimpleName(); } } // Maintenant, je passe aux implémentations concrète class SMSSender extends AbstractSender { public void send(String msg){ System.out.println("Envoi de "+msg+" par sms à "+recipient); } } class MailSender extends AbstractSender { public void send(String msg){ System.out.println("Envoi de "+msg+" par mail à "+recipient); } } class PigeonVoyageurSender extends AbstractSender { public void send(String msg){ System.out.println("Envoi de "+msg+" par pigeon voyageur à "+recipient+"!"); } } // Une "main" pour tester public static void main(String[] arg){ Sender s = new MailSender(); System.out.println(s); s.setRecipient("toto@toto.com"); s.send("Ceci est le message 1"); s = new PigeonVoyageurSender(); System.out.println(s); s.setRecipient("E32.3N45.5"); s.send("Ceci est le message 2"); }
Vu que j'y ai passé un peu de temps voici la version executable en interface, par contre je n'ai pas pensé au puigeon voyageur.
Faudra attendre un peu pour la version classe Abstraite.
Avant toute chose, "Pill_S" et"julien-blaise", je vous remercie pour les morceaux de code que vous avez établis.
Je me suis permis de modifier le code que tu m'as proposé en supprimant l'interface et en réintégrant la méthode "send" dans la classe abstraite "AbstractSender" :Envoyé par Pill_S
au final, le fonctionnement est le même.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75 /* * Main.java * * Created on 31 mai 2007, 14:36 * * To change this template, choose Tools | Template Manager * and open the template in the editor. */ package essai01; // D�clare l'interface d'un envoyeur /*interface Sender { void setRecipient(String s); void send(String msg); }*/ // Ici, je d�fini l'impl�mentation standard de tous les "Sender", par ex. "setRecipient(String)" qui permet d'affecter un destinataire // Les classes abstraites contiennent g�n�ralement des impl�mentations standards pouvant �tre modifi�s par les sous-classes abstract class AbstractSender /*implements Sender*/ { protected String recipient; public void setRecipient(String s) {recipient = s;} /* public void toString(){ return "Sender de classe "+getClass().getSimpleName(); }*/ public void send(String msg) { }; } // Maintenant, je passe aux impl�mentations concr�te class SMSSender extends AbstractSender { public void send(String msg){ System.out.println("Envoi de "+msg+" par sms � "+recipient); } } class MailSender extends AbstractSender { public void send(String msg){ System.out.println("Envoi de "+msg+" par mail � "+recipient); } } class PigeonVoyageurSender extends AbstractSender { public void send(String msg){ System.out.println("Envoi de "+msg+" par pigeon voyageur � "+recipient+"!"); } } /** * * @author Pierre */ public class Main { /** Creates a new instance of Main */ public Main() { } /** * @param args the command line arguments */ public static void main(String[] args) { // TODO code application logic here AbstractSender s = new MailSender(); System.out.println(s); s.setRecipient("toto@toto.com"); s.send("Ceci est le message 1"); s = new PigeonVoyageurSender(); System.out.println(s); s.setRecipient("E32.3N45.5"); s.send("Ceci est le message 2"); } }
Donc, dans ce cas précis, je ne vois pas l'intérêt des interfaces.
J'ai lu aussi la proposition qu'a faite "julien-blaise". Je n'y ai pas essayé de modification, mais il me semble que le principe est le même et que je peux y faire les mêmes actions.
A mon sens, (mais là, je me fais l'avocat du diable ... ne me frappez pas !) les "interfaces" ont été mises en place pour réintroduire l'héritage multiple qui n'était pas supporté au départ. Mais bon, je me trompe peut-être totalement.
Cordialement.
Pierre
C'est déjà pas mal de réintroduire l'héritage multiple même si il ne s'agit que de ça.
D'ailleurs attends que je te fasse la version classe abstraite, tu va voir la différence pour le coup
Je n'ai jamais dit le contraire. Et en y pensant, je m'aperçois que si on a un modèle à faire, autant en faire une interface qu'une classe abstraite car, sait-on jamais, on pourra la réutiliser en héritage multiple , si cela se présente..
Cordialement.
Pierre
Imaginez ce qu'aurait donner l'utilisation du framework des listeners dans swing sans utiliser des interface.
Mes 0.2€...
Comme il a déjà été dit, une interface est... une interface. C'est à dire ce que les clients de l'objet ont besoin de connaître pour pouvoir manipuler cet objet.
Concrètement, si tu veux conduire une voiture, tu as beson de connaitre le tableau de bord (volant, pédale, etc...) c'est à dire son "interface de pliotage". Après, il peut y avoir un moteur essence, diésel ou à vapeur, de ton point de vue de conducteur ça n'est pas important. De plus si l'interface de pilotage est la même, tu est également capable de conduire un hors bord, par exemple.
C'est ce concept qui est transcrit dans les interfaces java.
Tu peux très certainement t'en passer si ça te fait plaisir. Néanmoins qu'est ce qui est conceptuellement le plus juste ?
ou
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 class Voiture implements ITableauDeBord {} class HordBord implements ITableauDeBord {}
Le second cas signifie que Voiture et HorsBord sont des sortes particulières de TableauDeBord...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 class Voiture extends AbstractTableauDeBord {} class HorsBord extends AbstractTableauDeBord {}
Enfin il est parfois désirable de ne pas être obligé d'induire un couplage avec une seule et unique superclasse. Imagine que toutes les connections de base de données du monde dussent hériter de java.sql.AbstractConnection et que lors d'une mise à jour du JRE un codeur mal réveillé de Sun y introduise un bug bloquant !
Salut,
Envoyé par ChPrC'est tout à fait cela ! Toutefois j'ajouterais que si l'héritage multiple n'est pas supporté, c'est totalement volontaire. En effet ce dernier peut être amené à posé plus de problème qu'autre chose, en particulier lorsqu'on utilise majoritairement des méthodes virtuelles (c-a-d qui peuvent être redéfini dans les classes filles, et donc le comportement par défaut de Java).Envoyé par ChPr
Comme cela a été dit, les interfaces font plus état de contrat qu'autre chose. Et il ne faut pas les mettres en concurrence avec les classes abstraites qui ont un rôle assez différent : proposer une implémentation de base. Généralement on ne fait pas un choix entre interface et classe abstraite : on fait les deux.
En effet quel est le défaut de la version avec seulement des classes abtraites : il faut en hériter.
Et cela peut poser problème, un exemple : Imaginons que j'ai une classe j'ai une classe Developpez qui gère la session HTTP avec le forum (et l'authentification), et une classe fille MPSender permettant d'envoyer des messages privé sur le forum :
Je voudrais donner à cette classe le comportement de AbstractSender mais c'est impossible à cause de l'héritage multiple interdit....
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 class MPSender extends Developpez { public void mp(String user, String message) { System.out.println("Envoi d'un MP "+message+" a "+recipient+"!"); } }
Il me faudrait donc faire une nouvelle classe qui hérite d'AbstractSender et qui comporte une classe MPSender qui se chargera de l'envoi... Pas top
Avec une interface Sender il aurait suffit de faire implémenter l'interface et ses méthodes directement par la classe MPSender
Donc le mieux serait d'utiliser les deux à la fois : interface et classe abstraite (on peut même dire les trois avec les implémentations) :
- L'interface permet de définir le comportement général.
- La (les?) classe abstraite propose une implémentation de base (généralement incomplète), en impélmentant certaines méthodes basiques et/ou générale, mais également en proposant d'autre méthode utilise aux classes filles ou en apportant d'autre comportement (la gestion de Listener par exemple).
- Enfin, les implémentations héritent de la classe abtraite et la complète en implémentant les méthodes abstraites (voir d'autres) selon les besoins...
Voici donc comment j'aurai implémenté cela :
1. L'interface se contente de décrire le contrat et les méthodes (sans oublier la javadoc que je n'ai pas mis ici ) :
2. La classe abstraite implémente seulement la méthode setRecipient(). La méthode send() reste abstraite et devra être implémenté par les classes filles. Cette classe en profite également pour proposer une méthode getRecipient(), une redéfinition de toString() qui affiche le nom de la calsse et le destinataire, et propose enfin une gestion d'évenement lors des mdoifications des propriétées via les PropertyChangeListener :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 interface Sender { public void setRecipient(String s); public void send(String msg); }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 abstract class AbstractSender implements Sender { protected String recipient; // A ce niveaux, pas d'implémentation pour la méthode send() public abstract void send(String msg); // On implémente setRecipient() avec une gestion des listeners public void setRecipient(String s) { firePropertyChangeEvent("recipient", recipient, s); recipient = s; } // On implémente une méthode utilitaire supplémentaire : public String getRecipient() { return recipient; } // On redéfinit certaine méthode hérité de Object @Override public String toString() { return getClass().getSimpleName() + ":" + this.recipient; } // Et tout le neccessaire à la gestion des Listeners protected EventListenerList eventListenerList = new EventListenerList(); public void addPropertyChangeListener(PropertyChangeListener listener) { this.eventListenerList.add(PropertyChangeListener.class, listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { this.eventListenerList.remove(PropertyChangeListener.class, listener); } protected void firePropertyChangeEvent(String name, Object oldValue, Object newValue) { final PropertyChangeEvent evt = new PropertyChangeEvent(this, name, oldValue, newValue); for (PropertyChangeListener listener : this.eventListenerList.getListeners(PropertyChangeListener.class)) { listener.propertyChange(evt); } } }
3. Les implémentations de base sont identique aux votres (mais possèdent la gestion des listener et un 'joli' toString() ) :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 class SMSSender extends AbstractSender { public void send(String msg){ System.out.println("Envoi de "+msg+" par sms a "+recipient); } }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 class MailSender extends AbstractSender { public void send(String msg){ System.out.println("Envoi de "+msg+" par mail a "+recipient); } }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 class PigeonVoyageurSender extends AbstractSender { public void send(String msg){ System.out.println("Envoi de "+msg+" par pigeon voyageur a "+recipient+"!"); } }
Cette solution me permet à la fois d'avoir une interface qui me laisse totalement libre de l'implémentation, et une classe abstraite qui me propose une base commune
Ainsi, ma classe MPSender serait devenu :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 class MPSender extends Developpez implements Sender { public void mp(String user, String message) { System.out.println("Envoi d'un MP "+message+" a "+recipient+"!"); } protected String recipient; public void setRecipient(String s) { this.recipient = s; } public void send(String msg) { // Appel de la méthode mp : mp(this.recipient, msg); } }
Bien sûr il faut ensuire utiliser l'abstraction des implémentations, c'est à dire qu'on ne devrait pas utiliser les types AbstractSender ou les implémentations mais l'interface tant que c'est possible, c'est à dire qu'il NE FAUT PAS FAIRE :
Code : Sélectionner tout - Visualiser dans une fenêtre à part PigeonVoyageurSender s = new PigeonVoyageurSender();Mais :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 public void setSender(AbstractSender sender) { // ... }
Code : Sélectionner tout - Visualiser dans une fenêtre à part Sender s = new PigeonVoyageurSender();
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 public void setSender(Sender sender) { // ... }
Cette solution à trois niveaux est la meilleure à mon avis, d'ailleurs on la retrouve souvent dans l'API
- List -> AbstractList -> ArrayList, LinkedList
- Set -> AbstractSet -> HashSet, TreeSet
- Map -> AbstractMap -> HashMap, TreeMap
- TableModel -> AbstractTableModel -> DefaultTableModel
- etc.
a++
PS : j'ai encore fait un pavé... désolé
Même si ce sont des pavés, ce sont des explications claires et très bien argumentées ; et je vous en remercie.
Je vais maintenant essayer de digérer ces concepts (désolé, j'ai programmé 10 ans en objet DELPHI sans interface).
Cordialement.
Pierre
Partager