Expliquer les interfaces aux étudiants

Pendant quelques années, j’ai été assistant pédagogique pour une introduction au module de programmation Java pour les étudiants de première année.

La plupart du temps, tout s’est bien passé et nous avons réussi à bien transmettre la programmation orientée object aux élèves, mais les interfaces étaient une chose que les étudiants voyaient rarement.

Pratiquement toute explication que nous avons donnée soit apparue trop artificielle pour être utile à l’apprentissage, ou trop éloignée de leur position de débutant. La réaction que nous avons eue a été “Je … vois”, traduit par “Je ne comprends pas et ils ne semblent pas utiles”.

Quelqu’un ici a-t-il un moyen de réussir à enseigner aux étudiants les interfaces? Je ne suis plus un assistant d’enseignement, mais ça me harcèle toujours.

Si vous essayez de l’expliquer aux débutants, je m’en tiendrai à l’idée que les interfaces peuvent promouvoir la réutilisation du code et la modularité dans le code:

Par exemple, disons que nous allons peindre des objects:

public class Painter { private List paintableObjects; public Painter(){ paintableObjects = new ArrayList(); } public void paintAllObjects(){ for(Paintable paintable : paintableObjects){ paintable.paint(); } } } public interface Paintable { public void paint(); } 

Maintenant, vous pourriez expliquer aux étudiants que sans l’interface Paintable, l’object Painter devrait avoir des méthodes pour peindre certains types d’objects, comme une méthode appelée paintFences() et paintRocks() et qu’il faudrait une nouvelle Collection pour chaque type objects que nous voulons que le peintre puisse peindre.

Mais heureusement, nous avons des interfaces qui rendent la peinture des objects un jeu d’enfant et la façon dont les objects sont peints est laissée entièrement aux classes qui implémentent l’interface Paintable.

MODIFIER

Un autre avantage que j’ai oublié de mentionner est que si vous devez append un nouvel object à votre base de code, il vous suffit de créer une nouvelle classe qui implémente Paintable et la classe Painter ne doit jamais être modifiée. En ce sens, la classe Painter ne dépend jamais des objects qu’elle va peindre, elle doit seulement être capable de les peindre.

EDIT 2

James Raybould m’a rappelé une utilisation clé des interfaces que j’ai oublié de mentionner: Avoir une interface entre vos composants, comme les objects Paintable et les objects Painter, vous permet de développer plus facilement avec d’autres personnes. Un développeur peut travailler sur les objects Painter et un autre peut travailler sur les objects Paintable. Tout ce dont ils ont besoin pour fonctionner ensemble est de définir une interface commune qu’ils utiliseront tous les deux. Je sais que lorsque j’ai travaillé sur des projets avec d’autres personnes dans des projets de niveau collégial, c’est vraiment utile lorsque vous essayez que tout le monde travaille sur différentes parties du projet et que tous les composants se combinent bien à la fin.

En expliquant les interfaces et les concepts orientés object en général aux non-programmeurs, j’utilise toujours l’analogie du système de divertissement à domicile.

Le lecteur DVD, le téléviseur, le décodeur, la télécommande sont tous des objects qui encapsulent des fonctionnalités complexes et sophistiquées. Cependant, ils ont des interfaces les uns avec les autres et avec les humains qui les opèrent qui cachent en grande partie la part du lion de cette complexité.

La prise d’entrée vidéo d’un téléviseur est une interface implémentée par le lecteur DVD et le décodeur câble et par un certain nombre d’autres types d’appareils.

Je soupçonne qu’il serait possible et peut-être un exercice éducatif pour un étudiant de décrire son propre système de divertissement à la maison en utilisant le code Java.

“Là où les classes SONT quelque chose, généralement les interfaces font quelque chose. Donc je pourrais avoir une voiture, mais je ne ferais jamais de” carring “mais je conduirais peut-être … alors ma voiture pourrait mettre en place

MODIFIER:

Mark soulève un bon point. Les interfaces ne font rien du tout, mais définissent plutôt les comportements qui se produisent. Et, il soulève également un bon point à propos de ne pas vouloir confondre le public. Ce n’est pas bien de confondre les développeurs expérimentés, mais ce n’est certainement pas une bonne idée de confondre un nouvel étudiant. À la lumière de ceci, je révise mon one-liner dans un multi-liner.

“Où les classes définissent l’existence, les interfaces définissent le comportement. Les classes définissent ce que quelque chose est, alors que les interfaces définissent ce que fait quelque chose. Donc, j’ai une voiture, un moteur, une MPG historique, et pareil, mais je ne ferais jamais de “carring”. Je pourrais, d’autre part, aller conduire … est-ce que ma voiture peut conduire? Si je lui donne une méthode de conduite. Je peux aussi avoir une interface “pilotable” avec une méthode de conduite et laisser à la voiture le soin de déterminer ce que signifie réellement conduire. Maintenant, si je n’ai que des voitures, ce n’est pas grave d’avoir une interface, mais qu’en est-il des camions? Une List pour tous les deux. Bien sûr, l’étudiant observateur dit: «Pourquoi Car and Truck ne peut-il pas simplement étendre Vehicle, avec une méthode Drive abstraite?» Ce qui, en fait, est une notion très valable. Navette spatiale: très peu d’éléments entre la voiture et le camion s’appliquent à la navette spatiale. e Classe de véhicule. Ou les futures voitures? Nous n'avons aucune idée de ce à quoi ils pourraient ressembler, ils pourraient ne pas avoir de châssis, ils pourraient simplement être des bulles d'énergie qui nous font bouger, mais nous pourrions toujours appeler leur drive() comportement drive() . "

respire

Maintenant, ce paragraphe / essai est un peu verbeux, mais je pouvais voir, avec des diapositives ou un tableau, être efficace pour les étudiants de première année (en supposant qu'ils comprennent d'abord les classes abstraites).

Eh bien, je viens d’expliquer les interfaces à un partenaire de travail, elle apprend java à partir du progrès et elle n’a vraiment pas obtenu tous les trucs de la POO au début, alors j’ai tout expliqué d’un sharepoint vue comme ça:

Supposons que vous vouliez embaucher un plombier pour réparer certaines choses chez vous, vous ne savez pas (et vous vous moquez peu) de qui vous pourriez vous engager, mais vous savez ce que le plombier doit être capable de faire. Ainsi, vous définissez un ensemble de tâches que quiconque prétend être un plombier doit savoir faire. Bien sûr, tout le monde a sa propre façon d’exécuter chaque tâche, mais au final, la personne que vous embauchez est un plombier parce qu’elle sait comment faire chaque tâche. Donc, si vous écrivez ceci en Java, la première chose à faire serait de définir un plombier d’ interface comme ceci:

 public interface Plumber { //silly code here } 

Bon alors, disons que je sais comment faire chaque tâche que vous demandez et que je suis entièrement conforme à vos exigences et donc selon vous, je suis plombier. Donc, aujourd’hui je décide d’être votre plombier et vous décidez de l’engager (yay!), Sur la base du dernier exemple, vous pouvez dire que je suis une personne qui sait comment développer des logiciels et de la plomberie de manière spécifique, si Je devais écrire du code pour moi en tant que classe. Je pourrais écrire quelque chose comme ceci:

 public class Rick extends Person implements SoftwareDeveloper, Plumber 

et plus tard vous pourriez réparer les choses dans votre maison en utilisant moi comme votre plombier:

 Plumber thePlumber = rick; thePlumber.fixLeak(myHouse.bathroom.leak) // =( 

à partir de ce moment, les concepts de POO restants étaient faciles à expliquer.

Eh bien, récemment, je suis arrivé à expliquer cela à quelqu’un de proche. La façon dont j’ai expliqué la question “pourquoi Interfaces?”, Est en prenant exemple du port USB et des clés USB.

Le port USB peut être considéré comme une spécification et tout lecteur USB peut y entrer, à condition qu’ils implémentent la spécification. Donc, dans ce cas, le port devient l’interface et les nombreux types de clés USB disponibles deviennent la classe. Prenant cet exemple à l’avance, si je devais fournir à quelqu’un un lecteur USB (classe), je n’aurais pas besoin de lui dire (la méthode d’appel) ce que je transmets. Si la méthode d’appel avait pris une clé USB (type de classe) comme référence, je n’aurais pu transmettre que la clé USB à laquelle le port est destiné.

Pour résumer, Intefaces, aidez l’appelant à être compatible avec la méthode appelante (dans un cas d’utilisation lorsque la méthode appelante attend une instance d’un type particulier), quelle que soit l’instance transmise, l’appelant et l’appelé sont sûrs qu’il (instance) rentre dans la référence d’interface (le port USB pour l’analogie).

Class, nous avons passé les dernières sessions à implémenter le quicksort. Il était difficile de sortinger cette liste de personnes par leur nom. Que feriez-vous maintenant, si vous deviez sortinger cette liste par grade? Et que feriez-vous si vous deviez sortinger une liste de dinousaurs par âge? La seule façon de le savoir est de copier le code du sorting rapide et de modifier la comparaison et les types sur lesquels elle opère. Cela fonctionnerait – jusqu’à ce que vous trouviez ce bug insaisissable qui touchait toujours votre court-métrage, et que vous deviez le réparer en plusieurs dizaines de copies de ce quicksort éparpillé un peu partout.

Aujourd’hui, nous allons apprendre une meilleure façon.

Nous pouvons écrire un quicksort sans définir l’ordre dans lequel nous voulons sortinger la liste, et définir cet ordre (et uniquement cet ordre) séparément lorsque nous invoquons ce sorting rapide.

[insérer l’explication de la mécanique des interfaces et du polymorphism, en utilisant l’interface Comparator comme exemple, ici]

Maintenant, il n’y a qu’une seule copie de quicksort, et les bugs ne doivent être corrigés qu’une seule fois. En outre, les gens peuvent utiliser QuickSort sans le comprendre (ou s’ils l’ont compris, sans penser à sa mécanique chaque fois que vous voulez sortinger quelque chose). De plus, les personnes qui écrivent le court métrage n’ont pas besoin de connaître l’ordre dans lequel votre liste doit être sortingée. L’interface a donc isolé les deux groupes de programmeurs, leur permettant de développer leurs parties du logiciel isolément. C’est pourquoi, dans de nombreux langages de programmation, vous trouverez des méthodes de sorting bien implémentées et testées dans l’API, même si les programmeurs de ces méthodes ne peuvent pas connaître tous les types d’objects et les ordres que les utilisateurs souhaitent plus tard.

J’utilise habituellement le terme “contract” mais les “promesses solennelles de fournir” pourraient aussi aider à la compréhension.

Je recommande le premier chapitre de Head First Design Pattern s pour cela. La simulation de canard explique le problème de l’utilisation de l’inheritance, et le rest du chapitre explique comment procéder.

Ceci explique mieux: (référencé à partir de ce tutoriel )

Il existe un certain nombre de situations dans l’ingénierie logicielle lorsqu’il est important que des groupes de programmeurs disparates acceptent un «contrat» expliquant comment leurs logiciels interagissent. Chaque groupe doit pouvoir écrire son code sans savoir comment le code de l’autre groupe est écrit. De manière générale, les interfaces sont de tels contrats. Par exemple, imaginons une société futuriste où des voitures robotisées contrôlé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êtez, démarrez, accélérez, tournez à gauche, etc. Un autre groupe indussortingel, 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 utilise ces informations pour conduire la voiture.

Les constructeurs automobiles doivent publier une interface standard qui détaille les méthodes pouvant être utilisées pour déplacer la voiture (n’importe quelle voiture, de n’importe quel fabricant). Les fabricants de guides peuvent alors écrire des logiciels qui invoquent les méthodes décrites dans l’interface pour commander la voiture. Aucun groupe indussortingel n’a besoin de savoir comment le logiciel de l’autre groupe est implémenté. En fait, chaque groupe considère que son logiciel est hautement propriétaire et se réserve le droit de le modifier à tout moment, tant qu’il continue à adhérer à l’interface publiée.

Plus Lien: http://download-llnw.oracle.com/javase/tutorial/java/concepts/interface.html

Comprendre les interfaces n’est pas très différent de comprendre le polymorphism et les relations IS-A. Toutes les classes implémentant la même interface peuvent être manipulées de manière uniforme par le programme en tant que type “base” en raison de la relation établie en implémentant une interface ou en héritant d’une classe de base.

Le choix entre une interface et une classe de base est une décision de conception. Je garderais cela simple.

  • Définissez une classe lorsque votre implémentation peut assumer le comportement complet ou partiel d’une classe.
  • Rendre cette classe abstraite pour indiquer que la classe de base n’est pas une implémentation complète et ne peut pas être utilisée telle quelle.
  • Fournissez une interface à la place d’une classe de base si cela n’a pas de sens de fournir une implémentation partielle.

Les avantages des interfaces et de l’inheritance sont sensiblement les mêmes. Une interface est simplement une définition plus abstraite d’un type qu’une classe de base.

Mettre à jour

Voici un programme simple que vous pouvez utiliser pour démontrer à quel point l’inheritance et les interfaces sont similaires. Modifiez le programme pour faire de Base une interface au lieu d’une classe. Dans ClassA, remplacez “extend” pour “implements”. Le résultat du programme sera le même.

Le but de ClassB est d’illustrer davantage l’importance de la relation entre une classe et son interface / classe de base. Une instance de ClassB ne peut pas être transmise à processBase en dépit de ses similitudes avec Base, sauf si nous établissons une relation explicite.

 abstract class Base { public void behavior() {}; }; class ClassA extends Base { public void behavior() { System.out.println("ClassA implementation of Base behavior"); } }; class ClassB { public void behavior() { System.out.println("ClassB's version of behavior"); } } public class InterfaceExample { public void processBase (Base i) { i.behavior(); } public static void main (Ssortingng args[]) { InterfaceExample example = new InterfaceExample(); example.processBase(new ClassA()); } } 

Interface Oriented Design décrit cela mieux que je ne pourrais jamais le faire http://pragprog.com/titles/kpiod/interface-oriented-design . L’auteur utilise d’excellents exemples d’interfaces versus inheritance pour des choses comme la taxonomie du règne animal. Il présente certains des meilleurs arguments contre l’inheritance excessif et l’utilisation judicieuse des interfaces que j’ai lues jusqu’à présent.

Une bande de sites Web incompatibles:

Liste de Facebook.java :

 public class Facebook { public void showFacebook() { // ... } } 

Liste de YouTube.java :

 public class YouTube { public void showYouTube() { // ... } } 

Liste de StackOverflow.java :

 public class StackOverflow { public void showStackOverflow() { // ... } } 

Un client gérant manuellement les différentes méthodes utilisées par les sites Web pour se soulever:

Liste de ClientWithoutInterface.java :

 public class ClientWithoutInterface { public static void main(Ssortingng... args) { Ssortingng websiteRequested = args[0]; if ("facebook".equals(websiteRequested)) { new Facebook().showFacebook(); } else if ("youtube".equals(websiteRequested)) { new YouTube().showYouTube(); } else if ("stackoverflow".equals(websiteRequested)) { new StackOverflow().showStackOverflow(); } } } 

Introduire une interface Web pour faciliter le travail du client:

Liste de Website.java :

 public interface Website { void showWebsite(); } 

Liste de Facebook.java :

 public class Facebook implements Website { public void showWebsite() { // ... } } 

Liste de YouTube.java :

 public class YouTube implements Website { public void showWebsite() { // ... } } 

Liste de StackOverflow.java :

 public class StackOverflow implements Website { public void showWebsite() { // ... } } 

Liste de ClientWithInterface.java :

 public class ClientWithInterface { public static void main(Ssortingng... args) { Ssortingng websiteRequested = args[0]; Website website; if ("facebook".equals(websiteRequested)) { website = new Facebook(); } else if ("youtube".equals(websiteRequested)) { website = new YouTube(); } else if ("stackoverflow".equals(websiteRequested)) { website = new StackOverflow(); } website.showWebsite(); } } 

Whoop-de-doo, plus de code pour rien? En fait, nous pouvons aller un peu plus loin et demander à un couple d’amis de l’aider à trouver et à rendre un site Web demandé:

Liste de ClientWithALittleHelpFromFriends.java :

 public class ClientWithALittleHelpFromFriends { public static void main(Ssortingng... args) { WebsiteFinder finder = new WebsiteFinder(); WebsiteRenderer renderer = new WebsiteRenderer(); renderer.render(finder.findWebsite(args[0])); } } 

Liste de WebsiteFinder.java :

 public class WebsiteFinder { public Website findWebsite(Ssortingng websiteRequested) { if ("facebook".equals(websiteRequested)) { return new Facebook(); } else if ("youtube".equals(websiteRequested)) { return new YouTube(); } else if ("stackoverflow".equals(websiteRequested)) { return new StackOverflow(); } } } 

Liste de WebsiteRenderer.java :

 public class WebsiteRenderer { public void render(Website website) { website.showWebsite(); } } 

En regardant ClientWithoutInterface , il est totalement couplé à la recherche spécifique et au rendu basé. Il serait très difficile de gérer des centaines ou des milliers de sites. Avec l’interface du site Web en place, WebsiteFinder pourrait facilement être converti pour être sauvegardé sur une carte, une firebase database ou même une recherche basée sur le Web pour satisfaire une échelle croissante.

Les interfaces permettent de séparer un rôle du composant qui le réalise. Ils permettent d’échanger des solutions alternatives au même problème sur presque tout:

  • Charge actuelle sur la machine

  • Taille du jeu de données (les algorithmes de sorting peuvent être choisis)

  • Utilisateur demandant l’action en cours

Je tapais ceci comme un commentaire à la réponse de Harima555, mais cela s’est élargi. Je me demandais s’il était plus judicieux de commencer à l’autre bout du fil – donnez-leur une idée de la manière dont les interfaces sont utiles, avant de commencer à en écrire une.

En supposant qu’ils ont une bonne compréhension de l’inheritance, du polymorphism et des classes abstraites. Je commencerais probablement par un récapitulatif des cours de résumé, en demandant à l’un des élèves de les expliquer.

Ensuite, introduisez un exemple de classes avec des interfaces pour surmonter le concept de rôles / contrats. Pour simplifier les choses, commencez par une seule superclasse.

 public class Rick extends Person implements SoftwareDeveloper, Plumber public class Zoe extends Person implements SoftwareDeveloper, Chef public class Paul extends Person implements Plumber, Chef public class Lisa extends Person implements Plumber 

Ne l’expliquez pas trop, mais essayez de demander à l’étudiant de comprendre ce que la syntaxe pourrait signifier – peut-être en affichant un code faisant référence à un plombier ou à un développeur de logiciels.

Demandez-leur comment ils réaliseraient la même chose en utilisant l’inheritance de la personne. Ils doivent restr bloqués assez rapidement ou présenter des inheritances multiples. Pour éviter de discuter du problème du diamant jusqu’à plus tard, dites qu’il n’y a pas de méthodes qui se chevauchent dans les rôles.

Ensuite, j’essayerais de surmonter l’idée que la même interface peut être utilisée sur différents types de classes.

 public class Plane extends Vehicle implements Fly, PassengerTransport, Serviceable public class Train extends Vehicle implements PassengerTransport, Serviceable public class Bird extends Animal implements Fly 

Encore une fois, essayez de les amener à réfléchir à la manière dont ils pourraient implémenter la même chose en utilisant une super-classe et des substitutions communes.

Expliquez ensuite comment vous écririez du code polymorphe en utilisant l’interface plutôt que la classe – par exemple, un TravelAgent qui vend des tickets pour un PassengerTransport. Restez sur la force de ceci – que vous pouvez écrire du code polymorphe qui fonctionne sur des classes de différentes hiérarchies.

À ce stade, ils devraient probablement avoir l’illusion qu’une interface ressemble beaucoup à la possibilité d’append une autre superclasse à une classe et qu’elle aura compris les avantages de l’inheritance multiple.

Nous devons maintenant expliquer pourquoi cela complique les choses, et les interfaces ne sont pas implémentées par défaut, via la compréhension du problème des diamants.

Revenez au premier exemple, faites-les travailler sur ce qui se passe si SoftwareDeveloper et Plumber ont tous deux une méthode MakeDrink (l’un crée Cola, l’autre crée du café) et nous exécutons MakeDrink sur Rick.

Essayez de pousser quelqu’un à envisager l’idée que si MakeDrink rest abstrait dans les deux «superclasses», le problème disparaît. A ce stade, ayant le côté conceptuel, nous devrions être prêts à couvrir la syntaxe pour définir une interface.

(J’ai envisagé d’introduire la deuxième raison – la difficulté d’écrire du code générique qui pourrait être appliqué à différentes hiérarchies de classes, mais j’ai trouvé que vous ne pouvez pas hériter d’un atsortingbut d’altitude de l’interface ou discuter de la programmation générique trop tôt).

Je pense que maintenant nous aurions dû couvrir les concepts via les exemples de mickey mouse – et vous pourriez ensuite revenir en arrière en expliquant la terminologie technique correcte et en utilisant des exemples réels de l’API Java.

  • Je ne voudrais pas confondre les gens alors qu’ils essaient d’apprendre Java / Interfaces, mais une fois qu’ils l’ont compris, il peut être utile de souligner que d’autres langages OO adoptent des approches différentes du même problème, de l’inheritance multiple au piratage. en tapant – et s’ils sont intéressés, ils doivent les rechercher.

Est-ce que vous enseignez aussi JDBC? Prenez-le comme exemple. C’est un excellent exemple concret de la puissance des interfaces. Dans JDBC, vous écrivez du code sur une API qui ne contient que des interfaces. Le pilote JDBC est l’implémentation concrète. Vous pouvez facilement réutiliser le code JDBC sur de nombreuses bases de données sans réécrire le code. Il vous suffit de changer le fichier JAR d’implémentation du pilote JDBC et le nom de la classe du pilote pour qu’il fonctionne sur une autre firebase database.

Au moins, l’utilisation d’interfaces vous offre la possibilité de changer d’implémentation concrète (la logique du code qui est responsable du comportement) d’une manière / d’une autre sans réécrire le code entier. Essayez d’utiliser des exemples du monde réel pour expliquer les choses. Cela aurait plus de sens.

Eh bien, j’ai trouvé dernièrement une méthode très utile pour utiliser l’interface.

Nous avons beaucoup d’objects …

 public class Settings { Ssortingng[] keys; int values; } public class Car { Engine engine; int value; } public class Surface { int power; int elseInt; } // and maaany more (dozens...) 

Maintenant, quelqu’un crée (c’est-à-dire) une table et souhaite afficher certains objects de la liste de tous les objects, mais pour afficher les objects de la liste, il doit écrire la méthode qui renvoie Ssortingng [].

 Ssortingng[] toArraySsortingng() 

Donc, il implémente simplement cette méthode dans toutes les classes dont il a besoin dans la table

 public class Settings { Ssortingng[] keys; int values; public Ssortingng[] toArraySsortingng {...} } public class Car { Engine engine; int value; } // THIS NOT public class Surface { int power; int elseInt; public Ssortingng[] toArraySsortingng {...} } // and maaany more (dozens...) 

Maintenant, quand il crée la table, il écrit comme ça

 public void createTable() { for(Object obj : allObjects) { if(obj instanceof Settings) { Settings settings = (Settings)obj; table.add(settings.toArraySsortingng()); } if(obj instanceof Surface) { // cast... } // etc multiple times... } } 

Avec l’interface, ce code peut être beaucoup plus court et plus facile à lire et à gérer:

 public interface ISimpleInterface { Ssortingng[] toArraySsortingng; } public class Settings implements ISimpleInterface { Ssortingng[] keys; int values; public Ssortingng[] toArraySsortingng {...} } public class Car { Engine engine; int value; } // THIS NOT public class Surface implements ISimpleInterface { int power; int elseInt; public Ssortingng[] toArraySsortingng {...} } public void createTable() { for(Object obj : allObjects) { if(obj instanceof ISimpleInterface) { ISimpleInterface simple = (ISimpleInterface)obj; table.add(simple.toArraySsortingng()); } } } 

De plus, nous pouvons implémenter plusieurs interfaces de manière très propre et efficace sans aucune dérivation (la dérivation est parfois impossible et pas seulement au cas où la classe utilise déjà une autre dérivation).

Les interfaces donnent un aperçu de ce que doit faire une classe, par exemple, vous pouvez avoir une interface Animal et, par exemple, une méthode appelée speak (), bien que chaque animal puisse parler, mais tous le font différemment. met en œuvre l’animal à l’animal afin que vous puissiez avoir une liste d’animaux et les faire parler tous, mais utiliser leur propre implémentation. Les interfaces sont simplement des enveloppes pour ce genre de choses.

Dans cette question précédente, il y a quelques bons scénarios qui expliquent pourquoi utiliser des interfaces.

Question de débordement de stack

La valeur réelle des interfaces réside dans la possibilité de remplacer des composants dans des API ou des frameworks tiers. Je construirais une assignation où les étudiants doivent remplacer la fonctionnalité dans une bibliothèque pré-construite qu’ils ne peuvent pas changer (et pour laquelle ils n’ont pas la source).

Pour être plus concret, disons que vous avez un “framework” qui génère une page HTML implémentée en tant que classe Page. Et page.render (stream) génère le HTML. Disons que la page prend une instance de la classe sealed ButtonTemplate. L’object ButtonTemplate a sa propre méthode de rendu, de sorte que dans page.render (stream), buttonTemplate.render (label, stream) soit appelé n’importe où il y a un bouton et qu’il génère le HTML pour un bouton de soumission. En guise d’exemple aux étudiants, disons que nous voulons remplacer ces boutons de soumission par des liens.

Je ne leur donnerais pas beaucoup de direction autre que de décrire le résultat final. Ils devront taper la tête en essayant différentes solutions. “Devrions-nous essayer d’parsingr les balises de bouton et les remplacer par des balises d’ancrage? Peut-on sous-classer ButtonTemplate pour faire ce que nous voulons? Oh, attendez. C’est scellé! Que pensaient-ils lorsqu’ils ont scellé cette classe!? Ensuite, après cette affectation, affichez un second framework avec l’interface ILabeledTemplate avec la méthode de rendu (label, stream).

En plus des autres réponses, vous pouvez essayer de l’expliquer sous un angle différent. Les étudiants, j’en suis sûr, connaissent déjà l’inheritance car il est coincé dans la gorge de chaque élève de Java. Ont-ils entendu parler de l’inheritance multiple? La résolution de méthode était considérée comme un problème de conception en C ++ (et aussi en Perl et dans d’autres langages à inheritance multiple) car, sur le plan conceptuel, il était ambigu de savoir exactement ce qui devait arriver lorsqu’une méthode est appelée dans deux de ses classes de base. Sont tous deux exécutés? Lequel passe en premier? Peut-on être référencé spécifiquement? Voir aussi le problème des diamants . Je crois comprendre que cette confusion a été résolue simplement en introduisant des interfaces sans implémentation. Il n’ya donc aucune ambiguïté quant à la mise en œuvre à utiliser lors de la résolution de la méthode.

Si une classe devait gérer exactement une fonctionnalité abstraite et n’avait pas besoin d’hériter d’une autre classe , on pourrait utiliser une classe abstraite pour exposer la fonctionnalité et en déduire la classe réelle. Notez toutefois les deux éléments en italique. Les interfaces permettent à une classe de se comporter comme plusieurs types abstraits de choses abstraites, même si la classe est dérivée d’une autre classe qui ne se comporte pas comme ce genre de choses. Ainsi, les interfaces satisfont à l’un des principaux cas d’utilisation de l’inheritance multiple, sans la complexité inhérente à l’inheritance multiple.

Un exemple simple d’une interface très pratique: iEnumerable. Si une classe contient un nombre arbitraire d’un certain type d’élément, il est très utile qu’une autre classe agisse sur tous ces éléments sans avoir à se soucier des détails de l’object qui les contient. If “enumerableThing” were an abstract class, it would be impossible for an object of any class which derived from something that wasn’t an “enumerableThing” to be passed to code that expected an enumerableThing. Since any class, including derived classes, can implement enumerableThing without regard for whether the base classes do so, it’s possible to add enumeration ability to any class.

A long time ago, I read a book (can’t remember the name of it though) and it had a pretty good analogy for interfaces. If you (or your students) ever went to a Cold Stone Creamery ice cream store, this will sound kind of familiar. Cold Stone has ice cream and with the ice cream you can add several different things to the ice cream (called mix-ins at Cold Stone). These mix-ins would be analogous to interfaces. Your class (or ice cream) can have as many interfaces (or mix-ins) as you want. Adding an interface (or mix-in) will add the contents (or flavor) of that interface (or mix-in) to your class (or ice cream). J’espère que cela t’aides!

Contracts are first things that are taught about interfaces but they are built in the language to provide the skills of multiple inheritance and avoid the complexity of multiple inheritance.. So you can teach them that interfaces add runtime behaviour to programs, or you can tell the students that interfaces can be used to change runtime behaviour of objects..

First, the students must grasp the concept of abstractions. When you (you == the students) see a teacher, you can describe him as a teacher… You can also describe him as an employe (of the school). And you can describe him as a person. You will be right the three times. Thoses are “titles” you can give him.

He is a teacher, a computer science teacher, in the same way a math teacher is a teacher. They are on the same level of abstraction. Now a teacher is an employee, in the same way a janitor is an employee. They are on the same level of abstraction. An employe is a person, in the same way an unemployed person is a person. They are on the same level of abstraction.

(Draw the whole thing on the board in a UML kinda way).

And that’s the architecture that will describe (roughly) the position of a science teacher in society.

Now the levels of abstraction define what a common group of objects have in common : All the teachers teach to their students and create impossible exam questions to make sure they fail. All the school’s employes work for the school.

In programming, an interface is a level of abstraction. It describes the actions that a group of objects can accomplish. Each object has a unique way of doing the action, but the type of action is the same.

Take a few music instruments for example : A piano, a guitar and a flute. What do they have in common ? A musician can play them. You can’t ask a musician to blow in the 3 instruments but you can ask him to play them.

The architecture of the whole concept will be the following:

The Interface (what they have in common) is Instrument. Because they’re all instruments : it’s an abstraction they all have in common. What can they do in common ? Jouer. So you define an abstract method called Play.

Now you can’t define how the “Instrument” will play because it depends on the type of instrument. Flute is a type of Instrument. So the class Flute implements Instrument. Now you must define what the musician will do when he plays that type of instrument. So you define the play method. This definition will override the definition of the Instrument. Do the same with the 2 others instruments.

Now if you have a list of instruments but don’t know what type they are, you can still “ask” them to play. Each flute will be blown. Each guitar will be scratched. Each pianio will be … huh… pianoted ? whatever !

But each object will know what to do to execute the action “Play”. You don’t know what kind of instrument they are, but since you know they are instruments, you ask them to play and they know how to do that.

You may also want to compare and contrast interfaces in Java with C++ (where you end up using multiple inheritance and/or “friend” classes).

(At least, to me, that showed me how much simpler/easier interfaces were in Java 🙂

I would tell them “Interfaces define what behaviors are provided” and “Implementations provide those behaviors”. A piece of code that uses an interface doesn’t need the details of how things are happening, it only needs to know what things can happen.

A good example is the DAO pattern. It defines behavior like “save”, “load”, “delete”. You could have an implementation that works with a DB, and an implementation that goes to the file system.

I think a lot of the other answers so far are too complicated for students who don’t get it right away…

I think in general, hands-on learning always helps reinforce concepts after lectures and examples. So in the same vein as meriton suggests, I would present two versions of the same program. (quicksort is a good example)

Have the students modify each program several times, unveil subtle bugs in the program for them to fix. Your students will soon find, I think, that interfaces provide many advantages when designing a program when they’re the ones who have to modify it later!

I always think of it as a mean to (verbally) communicate as little as possible because that (good communication) is the most difficult thing in software engineering. Same for Web Services and SOA. If you give somebody an interface and say “Please provide me this service.” it is a very convenient way because you don’t have to explain a lot, and the comstackr will check if they did a proper job, instead of you! (I mean, not really but at least it’ll ensure the methods are there).