Alors disons que j'ai cette interface:
public interface IBox
{
public void setSize(int size);
public int getSize();
public int getArea();
//...and so on
}
Et j'ai une classe qui l'implémente:
public class Rectangle implements IBox
{
private int size;
//Methods here
}
Si je voulais utiliser l'interface IBox, je ne peux pas en créer une instance, de la manière:
public static void main(String args[])
{
Ibox myBox=new Ibox();
}
droite? Je devrais donc faire ceci:
public static void main(String args[])
{
Rectangle myBox=new Rectangle();
}
Si c'est vrai, alors le seul but des interfaces est de s'assurer que la classe qui implémente une interface contient les méthodes correctes comme décrit par une interface? Ou y a-t-il une autre utilisation des interfaces?
java
oop
language-features
interface
Cliquez sur Upvote
la source
la source
Réponses:
Les interfaces sont un moyen de rendre votre code plus flexible. Voici ce que vous faites:
Ensuite, plus tard, si vous décidez d'utiliser un autre type de boîte (peut-être qu'il y a une autre bibliothèque, avec un meilleur type de boîte), vous changez votre code en:
Une fois que vous vous y serez habitué, vous découvrirez que c'est une excellente façon (en fait essentielle) de travailler.
Une autre raison est, par exemple, si vous souhaitez créer une liste de boîtes et effectuer une opération sur chacune d'elles, mais que vous voulez que la liste contienne différents types de boîtes. Sur chaque boîte, vous pouvez faire:
(en supposant que IBox a une méthode close ()) même si la classe réelle de myBox change en fonction de la case dans laquelle vous vous trouvez dans l'itération.
la source
Ce qui rend les interfaces utiles, ce n'est pas le fait que "vous pouvez changer d'avis et utiliser une implémentation différente plus tard et avoir seulement à changer le seul endroit où l'objet est créé". Ce n'est pas un problème.
Le vrai point est déjà dans le nom: ils définissent une interface que n'importe qui peut implémenter pour utiliser tout le code qui opère sur cette interface. Le meilleur exemple est celui
java.util.Collections
qui fournit toutes sortes de méthodes utiles qui fonctionnent exclusivement sur des interfaces, telles quesort()
oureverse()
pourList
. Le point ici est que ce code peut maintenant être utilisé pour trier ou inverser toute classe qui implémente lesList
interfaces - pas seulementArrayList
etLinkedList
, mais aussi les classes que vous écrivez vous-même, qui peuvent être implémentées d'une manière que les personnes qui ont écritjava.util.Collections
n'ont jamais imaginé.De la même manière, vous pouvez écrire du code qui fonctionne sur des interfaces bien connues, ou des interfaces que vous définissez, et d'autres personnes peuvent utiliser votre code sans avoir à vous demander de prendre en charge leurs classes.
Une autre utilisation courante des interfaces est pour les rappels. Par exemple, java.swing.table.TableCellRenderer , qui vous permet d'influencer la façon dont une table Swing affiche les données dans une certaine colonne. Vous implémentez cette interface, passez une instance au
JTable
, et à un moment donné pendant le rendu de la table, votre code sera appelé pour faire son travail.la source
you can write code that operates on well-known interfaces, or interfaces you define
L'une des nombreuses utilisations que j'ai lues est celle où il est difficile sans interfaces d'utilisation d'héritage multiple en Java:
Maintenant, imaginez un cas où:
mais,
Une meilleure conception serait:
Animal n'a pas la méthode chew () et est à la place placé dans une interface comme:
et demandez à la classe Reptile d'implémenter ceci et non les oiseaux (puisque les oiseaux ne peuvent pas mâcher):
et en cas d'oiseaux simplement:
la source
Reptile
"mâche", alors pas lui-même est "à croquer". La convention de nommage (parfois) des interfaces Whateverable ne doit être appliquée que là où cela a un sens parfait. Nommer l'interfacePredator
serait plus approprié ici.Le but des interfaces est le polymorphisme , c'est-à-dire la substitution de type . Par exemple, étant donné la méthode suivante:
Lors de l'appel de la
scale
méthode, vous pouvez fournir toute valeur d'un type qui implémente l'IBox
interface. En d'autres termes, siRectangle
et lesSquare
deux implémententIBox
, vous pouvez fournir unRectangle
ou unSquare
partout où unIBox
est attendu.la source
Les interfaces permettent aux langages à typage statique de prendre en charge le polymorphisme. Un puriste orienté objet insisterait sur le fait qu'un langage devrait fournir l'héritage, l'encapsulation, la modularité et le polymorphisme afin d'être un langage orienté objet complet. Dans les langages à typage dynamique - ou canard - (comme Smalltalk,) le polymorphisme est trivial; cependant, dans les langages statiquement typés (comme Java ou C #), le polymorphisme est loin d'être trivial (en fait, à première vue, il semble être en contradiction avec la notion de typage fort.)
Laissez-moi vous démontrer:
Dans un langage typé dynamiquement (ou typé canard) (comme Smalltalk), toutes les variables sont des références à des objets (rien de moins et rien de plus.) Donc, dans Smalltalk, je peux faire ceci:
Ce code:
makeNoise
au cochon.Le même code Java ressemblerait à ceci (en supposant que Duck et Cow sont des sous-classes d'Animal:
C'est bien beau, jusqu'à ce que nous introduisions la classe Vegetable. Les légumes ont le même comportement que les animaux, mais pas tous. Par exemple, les animaux et les légumes peuvent pousser, mais il est clair que les légumes ne font pas de bruit et les animaux ne peuvent pas être récoltés.
Dans Smalltalk, nous pouvons écrire ceci:
Cela fonctionne parfaitement dans Smalltalk car il est typé canard (s'il marche comme un canard et charlatan comme un canard - c'est un canard.) Dans ce cas, lorsqu'un message est envoyé à un objet, une recherche est effectuée sur la liste des méthodes du récepteur, et si une méthode correspondante est trouvée, elle est appelée. Sinon, une sorte d'exception NoSuchMethodError est lancée - mais tout est fait au moment de l'exécution.
Mais en Java, un langage typé statiquement, quel type pouvons-nous attribuer à notre variable? Le maïs a besoin d'hériter de Vegetable, pour soutenir la croissance, mais ne peut pas hériter d'Animal, car il ne fait pas de bruit. La vache doit hériter d'Animal pour soutenir makeNoise, mais ne peut pas hériter de Vegetable car elle ne doit pas mettre en œuvre la récolte. Il semble que nous ayons besoin d' un héritage multiple - la possibilité d'hériter de plus d'une classe. Mais cela s'avère être une fonctionnalité de langage assez difficile à cause de tous les cas extrêmes qui apparaissent (que se passe-t-il lorsque plusieurs superclasses parallèles implémentent la même méthode?, Etc.)
Viennent les interfaces ...
Si nous créons des classes d'animaux et de légumes, à chaque implémentation de Growable, nous pouvons déclarer que notre vache est animale et notre maïs est légume. Nous pouvons également déclarer que les animaux et les légumes sont cultivables. Cela nous permet d'écrire ceci pour tout faire grandir:
Et cela nous permet de faire cela, de faire des bruits d'animaux:
L'avantage du langage de type canard est que vous obtenez un polymorphisme vraiment sympa: tout ce qu'une classe a à faire pour fournir un comportement est de fournir la méthode. Tant que tout le monde joue gentiment et n'envoie que des messages correspondant aux méthodes définies, tout va bien. L'inconvénient est que le type d'erreur ci-dessous n'est pas détecté avant l'exécution:
Les langages à typage statique fournissent une bien meilleure «programmation par contrat», car ils détecteront les deux types d'erreurs ci-dessous au moment de la compilation:
-
Alors ... pour résumer:
L'implémentation d'interface vous permet de spécifier les types de choses que les objets peuvent faire (interaction) et l'héritage de classe vous permet de spécifier comment les choses doivent être faites (implémentation).
Les interfaces nous offrent de nombreux avantages du "vrai" polymorphisme, sans sacrifier la vérification du type du compilateur.
la source
Normalement, les interfaces définissent l'interface que vous devez utiliser (comme son nom l'indique ;-)). Échantillon
Maintenant, votre fonction
foo
accepteArrayList
s,LinkedList
s, ... pas seulement un type.La chose la plus importante en Java est que vous pouvez implémenter plusieurs interfaces, mais vous ne pouvez étendre qu'une seule classe! Échantillon:
est possible mais n'est pas!Votre code ci - dessus pourrait aussi être:
IBox myBox = new Rectangle();
. L'important est maintenant que myBox contient UNIQUEMENT les méthodes / champs d'IBox et non les autres méthodes (éventuellement existantes) deRectangle
.la source
Je pense que vous comprenez tout ce que font les interfaces, mais vous n'imaginez pas encore les situations dans lesquelles une interface est utile.
Si vous instanciez, utilisez et libérez un objet dans une portée étroite (par exemple, dans un appel de méthode), une interface n'ajoute vraiment rien. Comme vous l'avez noté, la classe concrète est connue.
Là où les interfaces sont utiles, c'est lorsqu'un objet doit être créé à un endroit et renvoyé à un appelant qui peut ne pas se soucier des détails de l'implémentation. Changeons votre exemple IBox en Shape. Nous pouvons maintenant avoir des implémentations de Shape telles que Rectangle, Circle, Triangle, etc. Les implémentations des méthodes getArea () et getSize () seront complètement différentes pour chaque classe concrète.
Vous pouvez maintenant utiliser une fabrique avec une variété de méthodes createShape (params) qui renverront une forme appropriée en fonction des paramètres passés. Évidemment, la fabrique saura quel type de forme est créé, mais l'appelant n'aura pas se soucier de savoir si c'est un cercle, ou un carré, ou ainsi de suite.
Maintenant, imaginez que vous devez effectuer diverses opérations sur vos formes. Vous devez peut-être les trier par zone, les définir tous à une nouvelle taille, puis les afficher dans une interface utilisateur. Les formes sont toutes créées par l'usine et peuvent ensuite être transmises très facilement aux classes Sorter, Sizer et Display. Si vous devez ajouter une classe hexagonale dans le futur, vous n'avez rien à changer sauf l'usine. Sans l'interface, l'ajout d'une autre forme devient un processus très compliqué.
la source
vous pourriez faire
de cette façon, vous utilisez cet objet comme Ibox et vous ne vous souciez pas que ce soit vraiment
Rectangle
.la source
Square
vous auriez un problème .... si vous essayez de le faire sans interfaces, vous ne pouvez pas le garantirSquare
etRectangle
avoir les mêmes méthodes ... cela peut entraîner un cauchemar lorsque vous avez une base de code plus large ... N'oubliez pas que les interfaces définissent un modèle.POURQUOI INTERFACE ??????
Cela commence avec un chien. En particulier, un carlin .
Le carlin a différents comportements:
Et vous avez un Labrador, qui a également un ensemble de comportements.
Nous pouvons faire des carlins et des laboratoires:
Et nous pouvons invoquer leurs comportements:
Disons que je dirige un chenil et que je dois garder une trace de tous les chiens que je loge. J'ai besoin de stocker mes carlins et labradors dans des tableaux séparés :
Mais ce n'est clairement pas optimal. Si je veux aussi héberger des caniches , je dois changer ma définition de chenil pour ajouter un tableau de caniches. En fait, j'ai besoin d'un tableau distinct pour chaque type de chien.
Perspicacité: les carlins et les labradors (et les caniches) sont des types de chiens et ils ont le même ensemble de comportements. Autrement dit, nous pouvons dire (aux fins de cet exemple) que tous les chiens peuvent aboyer, avoir un nom et peuvent ou non avoir une queue bouclée. Nous pouvons utiliser une interface pour définir ce que tous les chiens peuvent faire, mais laisser aux types spécifiques de chiens le soin de mettre en œuvre ces comportements particuliers. L'interface dit "voici les choses que tous les chiens peuvent faire" mais ne dit pas comment chaque comportement est fait.
Ensuite, je modifie légèrement les classes Pug et Lab pour implémenter les comportements Dog. On peut dire qu'un carlin est un chien et qu'un laboratoire est un chien.
Je peux toujours instancier Pugs et Labs comme je le faisais auparavant, mais maintenant j'ai aussi une nouvelle façon de le faire:
Cela dit que d1 n'est pas seulement un chien, c'est spécifiquement un carlin. Et d2 est aussi un chien, en particulier un laboratoire. Nous pouvons invoquer les comportements et ils fonctionnent comme avant:
C'est là que tout le travail supplémentaire porte ses fruits. La classe Kennel devient beaucoup plus simple. J'ai besoin d'un seul tableau et d'une méthode addDog. Les deux fonctionneront avec n'importe quel objet qui est un chien; c'est-à-dire des objets qui implémentent l'interface Dog.
Voici comment l'utiliser:
Le dernier énoncé afficherait: Spot Fido
Une interface vous donne la possibilité de spécifier un ensemble de comportements que toutes les classes qui implémentent l'interface partageront en commun. Par conséquent, nous pouvons définir des variables et des collections (comme des tableaux) qui n'ont pas besoin de savoir à l'avance quel type d'objet spécifique elles contiendront, mais seulement qu'elles contiendront des objets qui implémentent l'interface.
la source
Un bon exemple de la façon dont les interfaces sont utilisées est dans le framework Collections. Si vous écrivez une fonction qui prend a
List
, peu importe si l'utilisateur passe unVector
ou unArrayList
ou unHashList
ou autre. Et vous pouvez également le transmettreList
à n'importe quelle fonction nécessitant une interfaceCollection
ouIterable
.Cela rend des fonctions comme
Collections.sort(List list)
possibles, quelle que soit la façon dont leList
.la source
C'est la raison pour laquelle les modèles d'usine et autres modèles de création sont si populaires en Java. Vous avez raison de dire que sans eux, Java ne fournit pas de mécanisme prêt à l'emploi pour une abstraction facile de l'instanciation. Pourtant, vous obtenez une abstraction partout où vous ne créez pas d'objet dans votre méthode, qui devrait être la majeure partie de votre code.
En passant, j'encourage généralement les gens à ne pas suivre le mécanisme "IRealname" pour nommer les interfaces. C'est une chose Windows / COM qui met un pied dans la tombe de la notation hongroise et qui n'est vraiment pas nécessaire (Java est déjà fortement typé, et tout l'intérêt d'avoir des interfaces est de les avoir aussi largement indiscernables que possible des types de classe).
la source
N'oubliez pas qu'à une date ultérieure, vous pouvez prendre une classe existante et la mettre en œuvre
IBox
, et elle deviendra alors disponible pour tout votre code compatible avec la boîte.Cela devient un peu plus clair si les interfaces sont nommées -able . par exemple
etc. (les schémas de dénomination ne fonctionnent pas toujours, par exemple je ne suis pas sûr que ce
Boxable
soit approprié ici)la source
Je mets à jour la réponse avec de nouvelles fonctionnalités d'interface, qui ont été introduites avec la version java 8 .
Depuis la page de documentation d'Oracle sur le résumé de l'interface :
Une déclaration d'interface peut contenir
Les seules méthodes qui ont des implémentations sont les méthodes par défaut et statiques.
Utilisations de l'interface :
Serializable
interface peuvent ou non avoir une relation entre elles, sauf implémenter cette interfaceQuelques questions SE liées concernant la différence entre la classe abstraite et l' interface et des cas d'utilisation avec des exemples de travail:
Quelle est la différence entre une interface et une classe abstraite?
Comment aurais-je dû expliquer la différence entre une interface et une classe abstraite?
Consultez la page de documentation pour comprendre les nouvelles fonctionnalités ajoutées dans java 8: méthodes par défaut et méthodes statiques .
la source
Le but des interfaces est l' abstraction ou le découplage de l'implémentation.
Si vous introduisez une abstraction dans votre programme, vous ne vous souciez pas des implémentations possibles. Vous êtes intéressé par ce qu'il peut faire et non par comment , et vous utilisez un
interface
pour exprimer cela en Java.la source
Si vous avez CardboardBox et HtmlBox (qui implémentent tous les deux IBox), vous pouvez les transmettre tous les deux à n'importe quelle méthode qui accepte un IBox. Même si elles sont toutes deux très différentes et pas complètement interchangeables, les méthodes qui ne se soucient pas de "ouvrir" ou de "redimensionner" peuvent toujours utiliser vos classes (peut-être parce qu'elles se soucient du nombre de pixels nécessaires pour afficher quelque chose sur un écran).
la source
Interfaces où une fétature ajoutée à java pour permettre l'héritage multiple. Les développeurs de Java ont cependant réalisé que l'héritage multiple était une fonctionnalité «dangereuse», c'est pourquoi ils ont eu l'idée d'une interface.
l'héritage multiple est dangereux car vous pourriez avoir une classe comme celle-ci:
Quelle serait la méthode qui devrait être appelée lorsque nous utilisons
Tous les problèmes sont résolus avec les interfaces, car vous savez que vous pouvez étendre les interfaces et qu'elles n'auront pas de méthodes de classement ... bien sûr, le compilateur est sympa et vous dit si vous n'avez pas implémenté de méthodes, mais j'aime penser que c'est un effet secondaire d'une idée plus intéressante.
la source
Voici ma compréhension de l'avantage de l'interface. Corrigez-moi si je me trompe. Imaginez que nous développons un système d'exploitation et qu'une autre équipe développe les pilotes pour certains appareils. Nous avons donc développé une interface StorageDevice. Nous en avons deux implémentations (FDD et HDD) fournies par d'autres équipes de développeurs.
Ensuite, nous avons une classe OperatingSystem qui peut appeler des méthodes d'interface telles que saveData en passant simplement une instance de classe implémentée l'interface StorageDevice.
L'avantage ici est que nous ne nous soucions pas de l'implémentation de l'interface. L'autre équipe fera le travail en implémentant l'interface StorageDevice.
la source