graphique - jtextfield java open classroom




Y at-il plus à une interface que d'avoir les bonnes méthodes (12)

le seul but des interfaces est de s'assurer que la classe qui implémente une interface a les bonnes méthodes comme décrit par une interface? Ou y a-t-il d'autres utilisations d'interfaces?

Je suis en train de mettre à jour la réponse avec de nouvelles fonctionnalités d'interface, qui ont été introduites avec la version 8 de Java .

De la page de documentation d'Oracle sur le résumé de l'interface :

Une déclaration d'interface peut contenir

  1. signatures de méthode
  2. méthodes par défaut
  3. méthodes statiques
  4. définitions constantes.

Les seules méthodes qui ont des implémentations sont les méthodes par défaut et statiques.

Utilisations de l'interface :

  1. Pour définir un contrat
  2. Lier des classes non liées avec des capacités (par exemple, les classes implémentant l'interface Serializable peuvent avoir ou non une relation entre elles sauf implémenter cette interface
  3. Pour fournir une implémentation interchangeable, par exemple un schéma de stratégie
  4. Les méthodes par défaut vous permettent d'ajouter de nouvelles fonctionnalités aux interfaces de vos bibliothèques et d'assurer la compatibilité binaire avec le code écrit pour les anciennes versions de ces interfaces
  5. Organisez les méthodes d'assistance dans vos bibliothèques avec des méthodes statiques (vous pouvez conserver des méthodes statiques spécifiques à une interface dans la même interface plutôt que dans une classe distincte)

Quelques questions SE liées à la différence entre la classe abstraite et l' interface et les cas d'utilisation avec des exemples de travail:

Quelle est la différence entre une interface et une classe abstraite?

Comment aurais-je expliqué la différence entre une interface et une classe abstraite?

Jetez un oeil à la page de documentation pour comprendre les nouvelles fonctionnalités ajoutées dans java 8: méthodes par défaut et méthodes statiques .

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 suivante:

public static void main(String args[])
{
    Ibox myBox=new Ibox();
}

droite? Donc je devrais réellement 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 a les bonnes méthodes comme décrit par une interface? Ou y a-t-il d'autres utilisations d'interfaces?


C'est la raison pour laquelle les motifs 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 un mécanisme prêt à l'emploi pour une abstraction facile de l'instanciation. Pourtant, vous obtenez l'abstraction partout où vous ne créez pas un objet dans votre méthode, ce 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 un truc 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 le point d'avoir des interfaces est de les avoir aussi facilement que possible des types de classes).


Interfaces où un fétiche ajouté à Java pour permettre l'héritage multiple. Les développeurs de Java ont réalisé que l'héritage multiple était une fonctionnalité "dangereuse", c'est pourquoi l'idée d'une interface est apparue.

l'héritage multiple est dangereux car vous pourriez avoir une classe comme celle-ci:


class Box{
    public int getSize(){
       return 0;
    }
    public int getArea(){
       return 1;
    }

}

class Triangle{
    public int getSize(){
       return 1;
    }
    public int getArea(){
       return 0;
    }

}

class FunckyFigure extends Box, Triable{
   // we do not implement the methods we will used the inherited ones
}

Quelle serait la méthode qui devrait être appelée lorsque nous utilisons


   FunckyFigure.GetArea(); 

Tous les problèmes sont résolus avec des interfaces, parce que vous savez que vous pouvez étendre les interfaces et qu'elles n'auront pas de méthodes de classification ... 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.


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 relâchez 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.

Lorsque les Interfaces sont utiles, c'est quand un objet doit être créé à un endroit et renvoyé à un appelant qui peut ne pas se soucier des détails d'implémentation. Transformons votre exemple IBox en une forme. Maintenant, nous pouvons 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.

Maintenant, vous pouvez utiliser une fabrique avec une variété de méthodes createShape (params) qui retourneront une forme appropriée en fonction des paramètres passés. Évidemment, l'usine 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 avez une variété d'opérations que vous devez effectuer sur vos formes. Peut-être que vous avez besoin de les trier par zone, les définir tous à une nouvelle taille, puis les afficher dans une interface utilisateur. Les formes sont toutes créées en usine et peuvent ensuite être facilement transmises aux classes Sorter, Sizer et Display. Si vous devez ajouter une classe hexagonale dans le futur, vous n'avez rien d'autre à changer que l'usine. Sans l'interface, l'ajout d'une autre forme devient un processus très compliqué.


Le but des interfaces est l' abstraction ou le découplage de la mise en œuvre.

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 comment , et vous utilisez une interface pour l'exprimer en Java.


Le but des interfaces est le polymorphisme , aussi appelé substitution de type . Par exemple, compte tenu de la méthode suivante:

public void scale(IBox b, int i) {
   b.setSize(b.getSize() * i);
}

Lorsque vous appelez la méthode scale , vous pouvez fournir n'importe quelle valeur d'un type qui implémente l'interface IBox . En d'autres termes, si Rectangle et Square implémentent tous deux IBox , vous pouvez fournir un Rectangle ou un Square chaque fois qu'un IBox est attendu.


Les interfaces sont un moyen de rendre votre code plus flexible. Ce que vous faites est ceci:

Ibox myBox=new Rectangle();

Ensuite, plus tard, si vous décidez d'utiliser un autre type de boîte (il existe peut-être une autre bibliothèque, avec un meilleur type de boîte), vous passez votre code à:

Ibox myBox=new OtherKindOfBox();

Une fois que vous vous y habituerez, vous constaterez que c'est une excellente façon de travailler.

Une autre raison est, par exemple, si vous voulez créer une liste de boîtes et effectuer une opération sur chacune d'elles, mais vous voulez que la liste contienne différents types de boîtes. Sur chaque boîte, vous pouvez faire:

myBox.close()

(en supposant que IBox a une méthode close ()) même si la classe réelle de myBox change en fonction de la boîte dans laquelle vous vous trouvez dans l'itération.


N'oubliez pas qu'à une date ultérieure, vous pouvez prendre une classe existante et l'implémenter dans IBox , et elle sera 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

public interface Saveable {
....

public interface Printable {
....

etc. (Les schémas de nommage ne fonctionnent pas toujours, par exemple je ne suis pas sûr que Boxable est approprié ici)


POURQUOI INTERFACE ??????

Ça commence avec un chien. En particulier, un carlin .

Le carlin a divers comportements:

public class Pug { 
private String name;
public Pug(String n) { name = n; } 
public String getName() { return name; }  
public String bark() { return  "Arf!"; } 
public boolean hasCurlyTail() { return true; } }

Et vous avez un Labrador, qui a aussi un ensemble de comportements.

public class Lab { 
private String name; 
public Lab(String n) { name = n; } 
public String getName() { return name; } 
public String bark() { return "Woof!"; } 
public boolean hasCurlyTail() { return false; } }

Nous pouvons faire des carlins et des labos:

Pug pug = new Pug("Spot"); 
Lab lab = new Lab("Fido");

Et nous pouvons invoquer leurs comportements:

pug.bark() -> "Arf!" 
lab.bark() -> "Woof!" 
pug.hasCurlyTail() -> true 
lab.hasCurlyTail() -> false 
pug.getName() -> "Spot"

Disons que je cours un chenil et j'ai besoin de 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 :

public class Kennel { 
Pug[] pugs = new Pug[10]; 
Lab[] labs = new Lab[10];  
public void addPug(Pug p) { ... } 
public void addLab(Lab l) { ... } 
public void printDogs() { // Display names of all the dogs } }

Mais ce n'est clairement pas optimal. Si je veux aussi loger des caniches , je dois changer ma définition de chenil pour ajouter un tableau de caniches. En fait, j'ai besoin d'un tableau séparé pour chaque type de chien.

Insight: 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 avoir ou non une queue bouclée. Nous pouvons utiliser une interface pour définir ce que tous les chiens peuvent faire, mais laisser le soin aux types spécifiques de chiens 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.

public interface Dog 
{
public String bark(); 
public String getName(); 
public boolean hasCurlyTail(); }

Ensuite, je modifie légèrement les classes Pug et Lab pour implémenter les comportements Dog. On peut dire qu'un Pug est un chien et qu'un Lab est un chien.

public class Pug implements Dog {
// the rest is the same as before } 

public class Lab implements Dog { 
// the rest is the same as before 
}

Je peux encore instancier Pugs and Labs comme je le faisais auparavant, mais maintenant j'ai aussi une nouvelle façon de le faire:

Dog d1 = new Pug("Spot"); 
Dog d2 = new Lab("Fido");

Cela dit que d1 n'est pas seulement un chien, c'est spécifiquement un roquet. Et d2 est aussi un chien, en particulier un laboratoire. Nous pouvons invoquer les comportements et ils fonctionnent comme avant:

d1.bark() -> "Arf!" 
d2.bark() -> "Woof!" 
d1.hasCurlyTail() -> true 
d2.hasCurlyTail() -> false 
d1.getName() -> "Spot"

Voici où tout le travail supplémentaire est payant. La classe Kennel devient beaucoup plus simple. Je n'ai besoin que d'un tableau et d'une méthode addDog. Les deux vont travailler avec n'importe quel objet qui est un chien; c'est-à-dire, les objets qui implémentent l'interface Dog.

public class Kennel {
Dog[] dogs = new Dog[20]; 
public void addDog(Dog d) { ... } 
public void printDogs() {
// Display names of all the dogs } }

Voici comment l'utiliser:

Kennel k = new Kennel(); 
Dog d1 = new Pug("Spot"); 
Dog d2 = new Lab("Fido"); 
k.addDog(d1); 
k.addDog(d2); 
k.printDogs();

La dernière déclaration affichera: Spot Fido

Une interface vous permet 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 ils vont contenir, mais seulement qu'ils contiendront des objets qui implémentent l'interface.


Si vous avez CardboardBox et HtmlBox (qui implémentent tous les deux IBox), vous pouvez passer 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 d'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).


vous pourriez faire

Ibox myBox = new Rectangle();

De cette façon, vous utilisez cet objet comme Ibox et vous ne vous souciez pas que c'est vraiment Rectangle .


Interfaces

Il existe un certain nombre de situations dans le domaine du génie logiciel lorsqu'il est important que des groupes disparates de programmeurs acceptent un «contrat» expliquant comment leur logiciel interagit. Chaque groupe devrait être capable d'écrire son code sans aucune connaissance de la façon dont le code de l'autre groupe est écrit. D'une manière générale, les interfaces sont de tels contrats.

Par exemple, imaginez une société futuriste où des voitures robotisées commandées par ordinateur transportent des passagers dans les rues de la ville sans opérateur humain. Les constructeurs automobiles écrivent des logiciels (Java, bien sûr) qui font fonctionner l'automobile: arrêter, démarrer, accélérer, tourner à gauche, etc. Un autre groupe industriel, les fabricants d'instruments de guidage électronique, fabrique des systèmes informatiques qui reçoivent des données de position GPS (Global Positioning System) et une transmission sans fil des conditions de circulation et utilisent ces informations pour conduire la voiture.

Les constructeurs automobiles doivent publier une interface normalisée qui précise en détail les méthodes qui peuvent être utilisées pour faire bouger la voiture (n'importe quelle voiture, de n'importe quel constructeur). Les fabricants de guidage peuvent alors écrire un logiciel qui invoque les méthodes décrites dans l'interface pour commander la voiture. Aucun groupe industriel n'a besoin de savoir comment le logiciel de l'autre groupe est implémenté. En effet, chaque groupe considère son logiciel comme hautement propriétaire et se réserve le droit de le modifier à tout moment, tant qu'il continue d'adhérer à l'interface publiée.







interface