854 votes

Que signifie « programmer en une interface » ?

Je l'ai vu mentionné à quelques reprises et je ne suis pas tout à fait clair sur ce que cela signifie. Quand et pourquoi voudriez-vous faire cela?

Je sais ce que les interfaces n', mais le fait que je ne suis pas clair sur ce me fait penser que je suis absent dehors sur de les utiliser correctement.

Est-il juste si vous le faites:

IInterface classRef = new ObjectWhatever()

Vous pouvez utiliser n'importe quelle classe qui implémente IInterface? Quand devez-vous faire? La seule chose que je peux penser est que si vous avez une méthode et vous n'êtes pas sûr de ce que l'objet sera passé à attendre pour cela la mise en œuvre de IInterface. Je ne vois pas comment souvent vous aurez besoin de faire ça... (d'ailleurs, comment pourriez-vous écrire une méthode qui prend un objet qui implémente une interface? Est-ce possible?)

Désolé si j'ai complètement manqué le point.


Questions supplémentaires:

  • fait à l'aide d'une Interface de frapper la performance?
  • si oui, combien?
  • comment pouvez-vous éviter de le faire sans avoir à maintenir deux morceaux de code?

1725voto

Peter Meyer Points 11163

Il y a quelques merveilleuses réponses ici à cette question dans toutes sortes de détails à propos des interfaces et vaguement couplage de code, l'inversion de contrôle et ainsi de suite. Il y a quelques assez capiteux des discussions, donc j'aimerais profiter de l'occasion pour briser les choses un peu pour comprendre pourquoi une interface est utile.

Quand j'ai commencé à recevoir des exposés à des interfaces, moi aussi j'ai été confus au sujet de leur pertinence. Je n'ai pas compris pourquoi vous avez besoin d'eux. Si nous utilisons un langage comme Java ou C#, nous avons déjà l'héritage et j'ai vu des interfaces comme les plus faibles de la forme de l'héritage et de la pensée, "pourquoi?" Dans un sens, j'étais de droite, vous pouvez penser à des interfaces comme une sorte de forme faible de l'héritage, mais au-delà de ce que j'ai finalement compris leur utilisation comme langue de construire en pensant à eux comme un moyen de classer les traits communs ou des comportements qui ont été exposées par de nombreux non-liées classes d'objets.

Par exemple, disons que vous avez un jeu de SIM et ont les classes suivantes:

 class HouseFly inherits Insect {
   void FlyAroundYourHead();
   void LandOnThings();
 }

 class Telemarketer inherits Person {
   void CallDuringDinner();
   void ContinueTalkingWhenYouSayNo();
 }

Clairement, ces deux objets n'ont rien en commun en termes d'héritage direct. Mais, vous pourriez dire qu'ils sont à la fois gênant.

Disons que notre jeu a besoin d'avoir une sorte de hasard chose qui agace le joueur de jeu quand ils mangent le dîner. Cela pourrait être une Mouche ou d'un Télévendeur ou les deux-mais comment voulez-vous permettre à la fois avec une seule fonction? Et comment voulez-vous demander à chaque type d'objet différent de "faire leur chose ennuyeuse" de la même manière?

La clé pour comprendre, c'est que à la fois un Télévendeur et Les partagent librement interprétée comportement, même si elles sont en rien semblables en termes de modélisation. Donc, nous allons faire une interface qui peut à la fois mettre en œuvre:

 interface IPest {
    void BeAnnoying();
 }


 class HouseFly inherits Insect implements IPest {
   void FlyAroundYourHead();
   void LandOnThings();

   void BeAnnoying() {
     FlyAroundYourHead();
     LandOnThings();
   }
 }

 class Telemarketer inherits Person implements IPest {
   void CallDuringDinner();
   void ContinueTalkingWhenYouSayNo();

   void BeAnnoying() {
      CallDuringDinner();
      ContinueTalkingWhenYouSayNo();
   }
 }

Nous avons maintenant deux classes qui peuvent chacune être gênant dans leur propre chemin. Et ils n'ont pas besoin de dériver de la même classe de base et ont en commun les caractéristiques inhérentes -- ils ont simplement besoin de satisfaire le contrat de IPest -- que le contrat est simple. Vous avez juste à BeAnnoying. À cet égard, nous pouvons modéliser le suivant:

 class DiningRoom {


   DiningRoom(Person[] diningPeople, IPest[] pests) { ... }

   void ServeDinner() {
     when diningPeople are eating,

       foreach pest in pests
         pest.BeAnnoying();
   }
 }

Ici, nous avons une salle à manger qui accepte un nombre de convives, et un certain nombre de ravageurs -- notez l'utilisation de l'interface. Cela signifie que dans notre petit monde, un membre de l' ravageurs tableau pourrait effectivement être un Télévendeur objet ou une Mouche objet.

Le ServeDinner méthode est appelée lorsque le dîner est servi et de notre peuple, dans la salle à manger sont censés manger. Dans notre petit jeu, c'est quand notre ravageurs faire leur travail-chaque ravageur est invité à être ennuyeux par la voie de l'IPest interface. De cette façon, nous pouvons facilement avoir à la fois des Télévendeurs et HouseFlys être gênant dans chacun de leurs propres moyens, nous nous soucions seulement que nous avons quelque chose dans la salle à manger objet qui est un ravageur, nous n'avons pas vraiment attention à ce qu'il est et qu'ils pourraient avoir rien en commun avec d'autres.

Cette très artificiel pseudo-code d'exemple (qui a traîné sur une beaucoup plus longue que ce que je pensais) est simplement d'illustrer le genre de chose qui a finalement tourné à la lumière pour moi en termes de quand on peut utiliser une interface. Je m'excuse d'avance pour la bêtise de l'exemple, et j'espère que cela vous aide dans votre compréhension. Et, bien sûr, les autres réponses que vous avez reçues d'ici vraiment couvrent toute la gamme, de l'utilisation des interfaces aujourd'hui dans la conception des modèles et des méthodologies de développement.

305voto

Bill the Lizard Points 147311

L'exemple que j'ai utilisé pour donner aux étudiants est qu'ils doivent écrire

List myList = new ArrayList(); // programming to the List interface

au lieu de

ArrayList myList = new ArrayList(); // this is bad

Ces exactement le même aspect dans un programme court, mais si vous continuez à utiliser myList 100 fois dans votre programme, vous pouvez commencer à voir une différence. La première déclaration qui vous garantit seulement l'appel de méthodes sur myList qui sont définis par l' List interface (donc pas de ArrayList méthodes spécifiques). Si vous avez programmé à l'interface de cette façon, plus tard, vous pouvez décider que vous avez vraiment besoin

List myList = new TreeList();

et vous n'avez qu'à changer votre code dans un seul endroit. Vous savez déjà que le reste de votre code n'est pas faire tout ce qui sera brisé par la modification de la mise en œuvre parce que vous avez programmé à l' interface.

80voto

kdgregory Points 21849

Programmation d'une interface est de dire "j'ai besoin de cette fonctionnalité et je ne me soucie pas d'où il vient."

Considérer (en Java), la Liste de l'interface par rapport à la ArrayList et LinkedList classes concrètes. Si tout ce qui m'intéresse, c'est que j'ai une structure de données contenant plusieurs éléments de données que je dois accès par itération, je choisirais la Liste (et c'est 99% du temps). Si je sais que j'ai besoin de constante de temps d'insérer ou de supprimer à partir de la fin de la liste, je pourrais choisir la LinkedList concrètes de mise en œuvre (ou, plus probablement, utilisez la File d'attente de l'interface). Si je sais que j'ai besoin d'un accès aléatoire par index, je choisirais la liste de tableaux de la classe de béton.

38voto

tvanfosson Points 268301

L'utilisation d'interfaces est un facteur clé dans la prise de votre code facilement testables en plus de supprimer les inutiles couplages entre vos classes. Par la création d'une interface qui définit les opérations sur votre classe, vous permettent à des classes qui veulent utiliser cette fonctionnalité, la capacité de l'utiliser sans en fonction de votre mise en œuvre de la classe directement. Si plus tard vous décidez de changer et d'utiliser une autre application, il vous suffit de changer la partie du code où la mise en œuvre est instancié. Le reste du code n'a pas besoin de changer, car il dépend de l'interface, pas la mise en œuvre de la classe.

Ceci est très utile dans la création de tests unitaires. Dans la classe sous test, vous l'avez dépendent de l'interface et de les injecter une instance de l'interface dans la classe (ou d'une usine qui permet de construire des instances de l'interface en fonction des besoins) par le constructeur ou une propriété settor. La classe utilise la condition (ou créé) de l'interface dans ses méthodes. Quand vous allez écrire vos tests, vous pouvez vous moquer ou faux l'interface et de fournir une interface qui réagit avec les données configurées dans votre unité de test. Vous pouvez le faire parce que votre classe de test ne traite que de l'interface, pas de votre mise en œuvre concrète. Toute classe implémentant l'interface, y compris votre maquette ou faux de la classe, va le faire.

EDIT: ci-Dessous un lien vers un article où Erich Gamma explique, je cite, "Programme pour une interface, pas une mise en œuvre".

http://www.artima.com/lejava/articles/designprinciples.html

36voto

Lasse V. Karlsen Points 148037

Vous devriez regarder dans l'Inversion de Contrôle:

Dans un tel scénario, vous ne pouvez pas écrire ceci:

IInterface classRef = new ObjectWhatever();

Vous pouvez écrire quelque chose comme ceci:

IInterface classRef = container.Resolve<IInterface>();

Ce serait aller dans une règle de base de l'installation dans l' container objet et la construction de l'objet réel pour vous, qui pourrait être ObjectWhatever. La chose importante est que vous pouvez remplacer cette règle avec quelque chose qui a utilisé un autre type d'objet tout à fait, et votre code fonctionne encore.

Si nous partons du Cio sur la table, vous pouvez écrire du code qui sait qu'il peut parler à un objet qui n'quelque chose de spécifique, mais pas le type de l'objet ou de la façon dont il le fait.

Ce serait très pratique lors du passage de paramètres.

Comme pour votre mise entre parenthèses de la question "comment, par ailleurs, pourriez-vous écrire une méthode qui prend un objet qui implémente une Interface? Est-ce possible?", en C#, vous pouvez tout simplement utiliser le type d'interface pour le type de paramètre, comme ceci:

public void DoSomethingToAnObject(IInterface whatever) { ... }

ce peut être branché directement dans le "parler à un objet qui n'est quelque chose de spécifique". La méthode définie ci-dessus, sait à quoi s'attendre à partir de l'objet, qu'il met tout en IInterface, mais il ne se soucie pas de quel type d'objet il s'agit, mais seulement qu'il respecte le contrat, qui est ce qu'une interface est vraiment.

Par exemple, vous êtes probablement familier avec les calculatrices et ont probablement utilisé un peu en vos jours, mais la plupart du temps, ils sont tous différents. Vous, en revanche, sait comment une calculatrice standard devrait fonctionner, de sorte que vous êtes en mesure de les utiliser tous, même si vous ne pouvez pas utiliser les fonctions spécifiques à chaque calculateur est qu'aucun des autres.

C'est la beauté des interfaces. Vous pouvez écrire un morceau de code, qui sait qu'elle permettra d'obtenir des objets du passé qu'il peut s'attendre à un certain comportement. Il ne s'occupe pas une huée quel type d'objet il s'agit, mais seulement qu'il prend en charge le comportement nécessaire.

Laissez-moi vous donner un exemple concret.

Nous avons un custom-built système de traduction pour windows forms. Ce système de boucles à travers les contrôles sur un formulaire, et traduit le texte dans chacune. Le système sait comment traiter les commandes de base, comme le type de contrôle-qui-a-un-Texte-propriété, et autres trucs de base, mais pour quoi que ce soit de base, il est court.

Maintenant, puisque les contrôles hériter de pré-définies les classes que nous n'avons aucun contrôle sur, nous pourrions faire une des trois choses:

  1. Renforcer le soutien dans notre système de traduction pour détecter spécifiquement le type de contrôle, il est travailler avec, et de traduire les bits corrects (entretien cauchemar)
  2. Renforcer le soutien dans les classes de base (ce qui est impossible, puisque tous les contrôles hériter de différents les classes pré-définies)
  3. L'interface d'ajout de support

Donc nous n'avons nr. 3. Toutes nos commandes en œuvre ILocalizable, qui est une interface qui nous donne qu'une seule méthode, la capacité de traduire "lui-même" par le biais d'un conteneur du texte de la traduction/règles. En tant que tel, le formulaire n'a pas besoin de connaître le type de contrôle qu'il a trouvé, seulement qu'il implémente l'interface, et sait qu'il existe une méthode de là, il peut appeler à localiser le contrôle.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X