Pourquoi ne puis-je pas saisir les interfaces?

Quelqu'un pourrait-il démystifier les interfaces pour moi ou me montrer de bons exemples? Je continue à voir des interfaces apparaître ici et là, mais je n'ai jamais vraiment été exposé à de bonnes explications sur les interfaces ou quand les utiliser.

Je parle d'interfaces dans un contexte d'interfaces par rapport aux classes abstraites.

49
demandé sur Peter Mortensen 2008-09-23 22:36:08

26 réponses

Les Interfaces vous permettent de programmer sur une "description" au lieu d'un type, ce qui vous permet d'associer plus librement des éléments de votre logiciel.

Pensez-y de cette façon: vous voulez partager des données avec quelqu'un dans le cube à côté de vous, de sorte que vous sortez votre bâton flash et copiez/collez. Vous marchez à côté et le gars dit " Est-ce USB?"et vous dites oui - tous ensemble. Peu importe la taille du Flash stick, ni le fabricant - Tout ce qui compte, c'est que C'est USB.

Dans le même de manière, les interfaces vous permettent de génériser votre développement. En utilisant une autre analogie-imaginez que vous vouliez créer une application qui a pratiquement peint les voitures. Vous pourriez avoir une signature comme ceci:

public void Paint(Car car, System.Drawing.Color color)...

Cela fonctionnerait jusqu'à ce que votre client dise "maintenant je veux peindre des camions" pour que vous puissiez faire ceci:

public void Paint (Vehicle vehicle, System.Drawing.Color color)...

Cela élargirait votre application... jusqu'à ce que votre client dise: "maintenant, je veux peindre des maisons!"Ce que vous auriez pu faire dès le début est créé un interface:

public interface IPaintable{
   void Paint(System.Drawing.Color color);
}

...et passé cela à votre routine:

public void Paint(IPaintable item, System.Drawing.Color color){
   item.Paint(color);
}

J'espère que cela a du sens-c'est une explication assez simpliste mais j'espère qu'elle va au cœur de celle-ci.

71
répondu Zaid 2010-09-05 15:56:14

Les Interfaces établissent un contrat entre une classe et le code qui l'appelle. Ils vous permettent également d'avoir des classes similaires qui implémentent la même interface mais font des actions ou des événements différents et ne pas avoir à savoir avec qui vous travaillez réellement. Cela pourrait avoir plus de sens à titre d'exemple, alors laissez-moi EN essayer un ici.

Dites que vous avez quelques classes appelées Chien, Chat et souris. Chacune de ces classes est un animal de compagnie et en théorie vous pourriez les hériter d'une autre classe appelée Pet mais voici le problème. Les animaux domestiques en eux-mêmes ne font rien. Vous ne pouvez pas aller au magasin et acheter un animal de compagnie. Vous pouvez aller acheter un chien ou un chat, mais un animal de compagnie est un concept abstrait et non concret.

Donc, vous savez que les animaux peuvent faire certaines choses. Ils peuvent dormir, ou manger, etc. Donc, vous définissez une interface appelée IPet et cela ressemble à ceci (syntaxe C#)

public interface IPet
{
    void Eat(object food);
    void Sleep(int duration);
}

Chacune de vos classes Chien, Chat et souris implémente IPet.

public class Dog : IPet

Alors maintenant, chacune de ces classes doit avoir propre mise en œuvre de manger et dormir. Yay vous avez un contrat... Maintenant, quel est le point.

Ensuite, disons que vous voulez créer un nouvel objet appelé PetStore. Et ce N'est pas un très bon PetStore donc ils vous vendent simplement un animal de compagnie aléatoire (Oui, je sais que c'est un exemple artificiel).

public class PetStore
{
     public static IPet GetRandomPet()
     {    
          //Code to return a random Dog, Cat, or Mouse
     } 
}

IPet myNewRandomPet = PetStore.GetRandomPet();
myNewRandomPet.Sleep(10);

Le problème est que vous ne savez pas quel type d'animal de compagnie, il sera. Merci à l'interface si vous savez quoi que ce soit, il va manger et dormir.

Donc, cette réponse n'a peut-être pas été utile du tout mais l'idée générale est que les interfaces vous permettent de faire des choses intéressantes comme L'Injection de dépendance et L'Inversion de contrôle où vous pouvez obtenir un objet, avoir une liste bien définie de choses que cet objet peut faire sans jamais vraiment savoir quel est le type concret de cet objet.

44
répondu JoshReedSchramm 2008-09-23 19:06:04

La réponse la plus simple est que les interfaces définissent ce que votre classe peut faire. C'est un "contrat" qui dit que votre classe sera capable de faire cette action.

Public Interface IRollOver
    Sub RollOver()
End Interface

Public Class Dog Implements IRollOver
    Public Sub RollOver() Implements IRollOver.RollOver
        Console.WriteLine("Rolling Over!")
    End Sub
End Class

Public Sub Main()
    Dim d as New Dog()
    Dim ro as IRollOver = TryCast(d, IRollOver)
    If ro isNot Nothing Then
        ro.RollOver()
    End If
End Sub

Fondamentalement, vous garantissez que la classe de chien a toujours la capacité de rouler tant qu'elle continue à implémenter cette Interface. Si les chats acquièrent la capacité de RollOver (), ils pourraient aussi implémenter cette interface, et vous pouvez traiter les chiens et les chats de manière homogène en leur demandant de RollOver().

33
répondu Bob King 2008-09-23 18:56:35

Quand vous conduisez la voiture d'un ami, vous savez plus ou moins comment le faire. En effet, les voitures conventionnelles ont toutes une interface très similaire: volant, pédales, etc. Pensez à cette interface comme un contrat entre les constructeurs automobiles et les conducteurs. En tant que conducteur (l'utilisateur/client de l'interface en termes de logiciel), vous n'avez pas besoin d'apprendre les particularités des différentes voitures pour pouvoir les conduire: par exemple, tout ce que vous devez savoir est que tourner le volant fait tourner la voiture. En tant que constructeur automobile (le fournisseur d'une implémentation de l'interface en termes de logiciel) vous avez une idée claire de ce que votre nouvelle voiture devrait avoir et comment elle devrait se comporter afin que les conducteurs puissent les utiliser sans beaucoup de formation supplémentaire. Ce contrat est ce que les gens dans la conception de logiciels appellent le découplage (l'utilisateur du fournisseur) - le code client est en termes d'utilisation d'une interface plutôt que d'une implémentation particulière de celle-ci et n'a donc pas besoin de connaître les détails des objets implémentant le interface.

16
répondu Alexander 2008-09-23 18:51:34

Les Interfaces sont un mécanisme permettant de réduire le couplage entre différentes parties, éventuellement disparates, d'un système.

Dans une perspective. net

  • La définition de l'interface est une liste d'opérations et / ou de propriétés.
  • les méthodes d'Interface sont toujours publiques.
  • l'interface elle-même n'a pas besoin d'être publique.

Lorsque vous créez une classe qui implémente l'interface, vous devez fournir une implémentation explicite ou implicite de toutes les méthodes et propriétés définies par l'interface.

En outre. net n'a qu'un seul héritage, et les interfaces sont une nécessité pour un objet d'exposer des méthodes à d'autres objets qui ne sont pas conscients ou qui se trouvent en dehors de sa hiérarchie de classes. Ceci est également connu sous le nom d'exposer les comportements.

Un exemple un peu plus concret:

Considérez que nous avons beaucoup de DTO (objets de transfert de données) qui ont des propriétés pour qui a mis à jour en dernier, et quand c'était. Le problème est que tous les DTO n'ont pas cette propriété parce que ce n'est pas toujours pertinent. En même temps, nous désirons un mécanisme générique pour garantir que ces propriétés sont définies si elles sont disponibles lorsqu'elles sont soumises au workflow, mais l'objet workflow doit être couplé de manière lâche à partir des objets soumis. c'est-à-dire que la méthode submit workflow ne devrait pas vraiment connaître toutes les subtilités de chaque objet, et tous les objets du workflow ne sont pas nécessairement des objets DTO.

// first pass - not maintainable
void SubmitToWorkflow(object o, User u)
{
  if( o is StreetMap )
  {
     var map = (StreetMap)o;
     map.LastUpdated = DateTime.UtcNow;
     map.UpdatedByUser = u.UserID;
  }
  else if( o is Person )
  {
     var person = (Person)o;
     person.LastUpdated = DateTime.Now; // whoops .. should be UtcNow
     person.UpdatedByUser = u.UserID;
  }
  // whoa - very unmaintainable.

Dans le code ci-dessus, SubmitToWorkflow() doit savoir A propos de chaque objet. De plus, le code est un gâchis avec un énorme if / else / switch, viole le principe de ne pas vous répéter (sec), et oblige les développeurs à se souvenir des changements de copier/coller chaque fois qu'un nouvel objet est ajouté au système.

// second pass - brittle
void SubmitToWorkflow(object o, User u)
{
  if( o is DTOBase )
  {
     DTOBase dto = (DTOBase)o;
     dto.LastUpdated = DateTime.UtcNow;
     dto.UpdatedByUser = u.UserID;
  }

Un peu mieux, mais toujours fragile. Si nous voulons soumettre d'autres types d'objets, nous avons encore besoin de plus d'instructions de cas. etc.

// third pass pass - also brittle
void SubmitToWorkflow(DTOBase dto, User u)
{
  dto.LastUpdated = DateTime.UtcNow;
  dto.UpdatedByUser = u.UserID;

Encore fragile, et les deux méthodes imposent la contrainte que tous les DTO doivent implémentez cette propriété que nous avons indiquée n'était pas universellement applicable. Certains développeurs pourraient être tentés d'écrire ne rien faire, mais qui sent mauvais. Nous ne voulons pas que les classes prétendent qu'elles prennent en charge le suivi des mises à jour, mais pas.

Interfaces, comment peuvent-elles aider?

Si nous définissons une interface très simple:

public interface IUpdateTracked
{
  DateTime LastUpdated { get; set; }
  int UpdatedByUser { get; set; }
}

Toute classe qui a besoin de ce suivi de mise à jour automatique peut implémenter l'interface.

public class SomeDTO : IUpdateTracked
{
  // IUpdateTracked implementation as well as other methods for SomeDTO
}

La méthode de workflow peut être faite pour être beaucoup plus Générique, plus petit et plus maintenable, et continuera à fonctionner peu importe le nombre de classes implémentant l'interface (DTO ou autre) car elle ne traite que de l'interface.

void SubmitToWorkflow(object o, User u)
{
  IUpdateTracked updateTracked = o as IUpdateTracked;
  if( updateTracked != null )
  {
     updateTracked.LastUpdated = DateTime.UtcNow;
     updateTracked.UpdatedByUser = u.UserID;
  }
  // ...
  • on peut noter que la variation void SubmitToWorkflow(IUpdateTracked updateTracked, User u) garantirait la sécurité du type, mais cela ne semble pas aussi pertinent dans ces circonstances.

Dans certains codes de production que nous utilisons, nous avons une génération de code pour créer ces classes DTO à partir de la définition de la base de données. La seule chose que le développeur fait il faut créer le nom du champ correctement et décorer la classe avec l'interface. Tant que les propriétés sont appelées LastUpdated et UpdatedByUser, cela fonctionne simplement.

Peut-être que vous demandez Que se passe-t-il si ma base de données est héritée et que ce n'est pas possible? Vous avez juste à faire un peu plus de frappe; une autre grande caractéristique des interfaces est qu'elles peuvent vous permettre de créer un pont entre les classes.

Dans le code ci-dessous, nous avons un LegacyDTO fictif, un pré-existant Objet ayant des champs de même nom. Il implémente L'interface IUpdateTracked pour combler les propriétés existantes, mais différemment nommées.

// using an interface to bridge properties
public class LegacyDTO : IUpdateTracked
{ 
    public int LegacyUserID { get; set; }
    public DateTime LastSaved { get; set; }

    public int UpdatedByUser
    {
        get { return LegacyUserID; }
        set { LegacyUserID = value; }
    }
    public DateTime LastUpdated
    {
        get { return LastSaved; }
        set { LastSaved = value; }
    }
}  

Vous pourriez chose Cool, mais n'est-ce pas déroutant d'avoir plusieurs propriétés? ou Que se passe-t-il s'il y a déjà ces propriétés mais qu'elles signifient autre chose?. Net vous donne la possibilité d'implémenter explicitement l'interface. Cela signifie que les propriétés IUpdateTracked ne seront visibles que lorsque nous sommes en utilisant une référence à IUpdateTracked. Notez qu'il n'y a pas de modificateur public sur la déclaration et que la déclaration inclut le nom de l'interface.

// explicit implementation of an interface
public class YetAnotherObject : IUpdatable
{ 
    int IUpdatable.UpdatedByUser
    { ... }
    DateTime IUpdatable.LastUpdated
    { ... }

Avoir autant de flexibilité pour définir comment la classe implémente l'interface donne au développeur beaucoup de liberté pour découpler l'objet des méthodes qui le consomment. Les Interfaces sont un excellent moyen de briser le couplage.

Il y a beaucoup plus d'interfaces que cela. Ceci est juste un exemple simplifié de la vie réelle qui utilise un aspect de la programmation basée sur l'interface.

Comme je l'ai mentionné précédemment, et par d'autres intervenants, vous pouvez créer des méthodes qui prennent et / ou renvoient des références d'interface plutôt qu'une référence de classe spécifique. Si j'avais besoin de trouver des doublons dans une liste, je pourrais écrire une méthode qui prend et renvoie un IList (une interface définissant des opérations qui fonctionnent sur des listes) et je ne suis pas contraint à une classe de collection concrète.

// decouples the caller and the code as both 
// operate only on IList, and are free to swap
// out the concrete collection.
public IList<T> FindDuplicates( IList<T> list )
{
    var duplicates = new List<T>()
    // TODO - write some code to detect duplicate items
    return duplicates;
}

Mise en garde Versioning

Si c'est un public interface, vous déclarez je vous garantis que l'interface x ressemble à ceci!{[28] } et une fois que vous avez expédié le code et publié l'interface, vous ne devriez jamais le changer. Dès que le code de consommation commence à compter sur cette interface, vous ne voulez pas casser leur code sur le terrain.

Voir ce Haacked post - pour une bonne discussion.

Interfaces versus classes abstraites (de base)

Les classes abstraites peuvent fournir une implémentation alors que les Interfaces ne le peuvent pas. Abstrait les classes sont à certains égards plus flexibles dans l'aspect versioning si vous suivez certaines directives comme le modèle nvpi (Non-Virtual Public Interface).

, Il est bon de répéter que, dans .net, une classe ne peut hériter que d'une seule classe, mais une classe peut implémenter autant d'interfaces qu'elle aime.

Injection De Dépendance

Le résumé rapide des interfaces et DI est que l'utilisation des interfaces permet aux développeurs d'écrire du code qui est programmé contre une interface pour fournir des services. En pratique, vous pouvez vous retrouver avec beaucoup de petites interfaces et de petites classes, et une idée est que les petites classes qui font une chose et une seule chose sont beaucoup plus faciles à coder et à maintenir.

class AnnualRaiseAdjuster
   : ISalaryAdjuster
{
   AnnualRaiseAdjuster(IPayGradeDetermination payGradeDetermination) { ...  }

   void AdjustSalary(Staff s)
   {
      var payGrade = payGradeDetermination.Determine(s);
      s.Salary = s.Salary * 1.01 + payGrade.Bonus;
   }
}

En bref, l'avantage indiqué dans l'extrait ci-dessus est que la détermination de la classe de rémunération est simplement injectée dans l'ajusteur d'augmentation annuelle. La façon dont la note salariale est déterminée n'a pas d'importance pour cette classe. Lors du test, le développeur peut simuler les résultats de la détermination de la note de salaire pour assurez-vous que l'Ajusteur de salaire fonctionne comme vous le souhaitez. Les tests sont également rapides car le test ne teste que la classe, et pas tout le reste.

Ce n'est pas une amorce DI cependant car il y a des livres entiers consacrés au sujet; l'exemple ci-dessus est très simplifié.

14
répondu Robert Paulson 2018-06-28 13:36:16

C'est un sujet assez "long", mais permettez-moi d'essayer de le simplifier.

Une interface est-comme "ils l'appellent" - un contrat. Mais oublier ce mot.

La meilleure façon de les comprendre est à travers une sorte d'exemple de pseudo-code. C'est comme ça que je les ai compris il y a longtemps.

Supposons que vous ayez une application qui traite les Messages. Un Message contient des choses, comme un sujet, un texte, etc.

Donc, vous écrivez votre MessageController pour lire une base de données, et extraire message. C'est très agréable jusqu'à ce que vous entendiez soudainement que les télécopies seront également implémentées bientôt. Donc, vous devrez maintenant lire " fax " et les traiter comme des messages!

Cela pourrait facilement se transformer en un code Spagetti. Donc, ce que vous faites au lieu d'avoir un MessageController que les contrôles "Messages" seulement, vous le rendez capable de travailler avec une interface appelée IMessage (le I est juste un usage commun, mais pas nécessaire).

Votre interface IMessage contient des données de base dont vous avez besoin pour vous assurer que vous êtes en mesure de traiter le Message en tant que tel.

Ainsi, lorsque vous créez vos classes EMail, Fax, PhoneCall, vous les faites implémenter l'Interface {[16] appelée IMessage .

, Donc dans votre MessageController, vous pouvez avoir une méthode appelée comme ceci:

private void ProcessMessage(IMessage oneMessage)
{
    DoSomething();
}

Si vous n'aviez pas utilisé D'Interfaces, vous devriez avoir:

private void ProcessEmail(Email someEmail);
private void ProcessFax(Fax someFax);
etc.

Donc, en utilisant une interface commune , vous venez de vous assurer que la méthode ProcessMessage sera capable de travailler avec, peu importe s'il s'agissait D'un Fax, D'un E-Mail, D'un appel téléphonique, etc.

Pourquoi ou comment?

Parce que l'interface est un contrat qui spécifie certaines choses que vous devez respecter (ou implémenter) pour pouvoir l'utiliser. Pensez-y comme un insigne. Si votre objet " Fax " n'a pas L'interface IMessage, votre méthode ProcessMessage ne pourrait pas fonctionner avec cela, elle vous donnera un type invalide, car vous passez un Fax à une méthode qui attend un objet IMessage.

Voyez-vous l'intérêt?

Pensez à l'interface comme un "sous-ensemble" de méthodes et de propriétés que vous aurez disponibles, malgré le type d'objet réel. Si l'objet d'origine (Fax, Email, appel téléphonique, etc.) implémente cette interface, vous pouvez la transmettre en toute sécurité à travers les méthodes qui ont besoin de cette Interface.

Il y a plus de magie cachée là-dedans, vous pouvez renvoyer les interfaces à leurs objets d'origine:

Fax myFax = (Fax)SomeIMessageThatIReceive;

L'ArrayList () dans. net 1.1 avait une belle interface appelée IList. Si vous aviez un IList (très "générique"), vous pourriez le transformer en ArrayList:

ArrayList ar = (ArrayList)SomeIList;

Et il y a des milliers d'échantillons dans la nature.

Interfaces comme ISortable, IComparable, etc., définissez les méthodes et les propriétés que vous devez implémenter dans votre classe afin d'atteindre cette fonctionnalité.

Pour élargir notre échantillon, vous pourriez avoir une liste de Emails, Fax, Appel Téléphonique, tous dans la même Liste, si le Type est IMessage, mais vous ne pourriez pas les avoir tous ensemble si les objets étaient simplement Email, Fax, etc.

Si vous voulez trier (ou énumérer par exemple) vos objets, vous en aurez besoin pour implémenter l'interface correspondante. Dans L'exemple. net, si vous avez une liste d'objets " Fax " et que vous voulez pouvoir les trier en utilisant MyList.Sort (), vous avez besoin de pour créer votre classe fax comme ceci:

public class Fax : ISorteable 
{
   //implement the ISorteable stuff here.
}

J'espère que cela vous donne un indice. D'autres utilisateurs publieront éventuellement d'autres bons exemples. Bonne chance! et embrasser la puissance des INterfaces.

Attention : Tout n'est pas bon sur les interfaces, il y a quelques problèmes avec eux, les puristes de la POO vont commencer une guerre à ce sujet. Je doit rester de côté. Un inconvénient D'une Interfce (dans. net 2.0 au moins) est que vous ne pouvez pas avoir de membres privés, ou protégé, il doit {[20] } être public. Cela a du sens, mais parfois vous souhaitez que vous pourriez simplement déclarer les choses comme privées ou protégées.

6
répondu Martin Marconcini 2008-09-23 18:57:13

En plus des fonctions que les interfaces ont dans les langages de programmation, elles sont également un outil sémantique puissant pour exprimer des idées de conception à d'autres personnes.

Une base de code avec des interfaces bien conçues est soudainement beaucoup plus facile à discuter. "Oui, vous avez besoin D'un CredentialsManager pour enregistrer de nouveaux serveurs distants.""Passez une PropertyMap à ThingFactory pour obtenir une instance de travail."

La capacité d'aborder une chose complexe avec un seul mot est très utile.

5
répondu Internet Friend 2008-09-23 19:01:44

Les Interfaces vous permettent de coder des objets de manière générique. Par exemple, disons que vous avez une méthode qui envoie des rapports. Maintenant, dites que vous avez une nouvelle exigence qui vient là où vous devez écrire un nouveau rapport. Ce serait bien si vous pouviez réutiliser la méthode que vous aviez déjà écrite? Interfaces rend cela facile:

interface IReport
{
    string RenderReport();
}

class MyNewReport : IReport
{
    public string RenderReport()
    {
        return "Hello World Report!";

    }
}

class AnotherReport : IReport
{
    public string RenderReport()
    {
        return "Another Report!";

    }
}

//This class can process any report that implements IReport!
class ReportEmailer()
{
     public void EmailReport(IReport report)
     {
         Email(report.RenderReport());
     }
}

class MyApp()
{
    void Main()
    {
        //create specific "MyNewReport" report using interface
        IReport newReport = new MyNewReport();

        //create specific "AnotherReport" report using interface
        IReport anotherReport = new AnotherReport();

        ReportEmailer reportEmailer = new ReportEmailer();

        //emailer expects interface
        reportEmailer.EmailReport(newReport);
        reportEmailer.EmailReport(anotherReport);



    }

}
4
répondu Giovanni Galbo 2008-09-23 19:00:49

Les Interfaces sont également la clé du polymorphisme, l'un des "trois piliers de OOD".

Certaines personnes évoqué ci-dessus, le polymorphisme signifie simplement une classe donnée peut prendre différentes "formes". Signification, si nous avons deux classes, "chien" et "Chat" et les deux implémentent l'interface "INeedFreshFoodAndWater" (hehe) - votre code peut faire quelque chose comme ceci (pseudocode):

INeedFreshFoodAndWater[] array = new INeedFreshFoodAndWater[];
array.Add(new Dog());
array.Add(new Cat());

foreach(INeedFreshFoodAndWater item in array)
{
   item.Feed();
   item.Water();
}

Ceci est puissant car il vous permet de traiter différentes classes d'objets de manière abstraite, et vous permet de faire des choses comme Rendre vos objets plus vaguement couplés, etc.

4
répondu Sam Schutte 2008-09-23 19:09:28

OK, il s'agit donc de classes abstraites par rapport aux interfaces...

Conceptuellement, les classes abstraites sont là pour être utilisées comme classes de base. Très souvent, ils fournissent eux-mêmes déjà des fonctionnalités de base, et les sous-classes doivent fournir leur propre implémentation des méthodes abstraites (ce sont les méthodes qui ne sont pas implémentées dans la classe de base abstraite).

Les Interfaces sont principalement utilisées pour découpler le code client des détails d'une implémentation particulière. Également, parfois, la possibilité de changer l'implémentation sans changer le code client rend le code client plus générique.

Au niveau technique, il est plus difficile de tracer la ligne entre les classes abstraites et les interfaces, car dans certains langages (par exemple, C++), il n'y a pas de différence syntaxique, ou parce que vous pouvez également utiliser des classes abstraites à des fins de découplage ou de généralisation. L'utilisation d'une classe abstraite comme interface est possible car chaque classe de base, par définition, définit une interface que toutes ses sous-classes devraient honorer (c'est-à-dire qu'il devrait être possible d'utiliser une sous-classe au lieu d'une classe de base).

3
répondu Alexander 2008-09-23 19:06:54

Les Interfaces sont un moyen d'appliquer qu'un objet implémente une certaine quantité de fonctionnalités, sans avoir à utiliser l'héritage (ce qui conduit à un code fortement couplé, au lieu d'un couplage lâche qui peut être réalisé en utilisant des interfaces).

Les Interfaces décrivent la fonctionnalité, pas l'implémentation.

2
répondu Darren Kopp 2008-09-23 19:02:37

En termes simples: une interface est une classe que les méthodes définies mais aucune implémentation en eux. En revanche, une classe abstraite a certaines des méthodes implémentées mais pas toutes.

1
répondu Spoike 2008-09-23 18:50:14

Pensez à une interface comme un contrat. Lorsqu'une classe implémente une interface, elle accepte essentiellement d'honorer les termes de ce contrat. En tant que consommateur, vous vous souciez seulement que les objets que vous avez puissent accomplir leurs tâches contractuelles. Leur fonctionnement interne et les détails ne sont pas importants.

1
répondu Kevin Pang 2008-09-23 18:55:24

Une bonne raison d'utiliser une interface par rapport à une classe abstraite en Java est qu'une sous-classe ne peut pas étendre plusieurs classes de base, mais elle peut implémenter plusieurs interfaces.

1
répondu Eric Asberry 2008-09-23 19:30:28

Java n'autorise pas l'héritage multiple (pour de très bonnes raisons, recherchez dreadful diamond) mais que faire si vous voulez que votre classe fournisse plusieurs ensembles de comportement? Dites que vous voulez que quiconque l'utilise sache qu'il peut être sérialisé, et aussi qu'il peut se peindre sur l'écran. la réponse est d'implémenter deux interfaces différentes.

Parce que les interfaces ne contiennent aucune implémentation de leur propre et aucun membre d'instance, il est sûr d'implémenter plusieurs d'entre elles dans la même classe sans ambiguïté.

L'inconvénient est que vous devrez avoir l'implémentation dans chaque classe séparément. Donc, si votre hiérarchie est simple et qu'il y a des parties de l'implémentation qui devraient être les mêmes pour toutes les classes héritées, utilisez une classe abstraite.

1
répondu user21334 2008-09-23 19:39:40

Comme d'autres l'ont dit ici, les interfaces définissent un contrat (comment les classes qui utilisent l'interface vont "regarder") et les classes abstraites définissent les fonctionnalités partagées.

Voyons si le code AIDE:

public interface IReport
{
    void RenderReport(); // this just defines the method prototype
}

public abstract class Reporter
{
    protected void DoSomething()
    {
        // this method is the same for every class that inherits from this class
    }
}

public class ReportViolators : Reporter, IReport
{
    public void RenderReport()
    {
        // some kind of implementation specific to this class
    }
}

public class ClientApp
{
    var violatorsReport = new ReportViolators();

    // the interface method
    violatorsReport.RenderReport();

    // the abstract class method
    violatorsReport.DoSomething();
}
1
répondu Robert S. 2008-09-23 19:46:33

En supposant que vous faites référence à des interfaces dans des langages orientés objet typés statiquement, l'utilisation principale consiste à affirmer que votre classe suit un contrat ou un protocole particulier.

Dites que vous avez:

public interface ICommand
{
    void Execute();
}
public class PrintSomething : ICommand
{
    OutputStream Stream { get; set; }
    String Content {get; set;}
    void Execute()
    { 
        Stream.Write(content);
    }
}

Maintenant, vous avez une structure de commande substituable. Toute instance d'une classe qui implémente IExecute peut être stockée dans une liste quelconque, dire quelque chose qui implémente IEnumerable et vous pouvez parcourir cela et exécuter chacun, sachant que chaque objet fera simplement le La Bonne Chose. Vous pouvez créer une commande composite en implémentant CompositeCommand qui aura sa propre liste de commandes à exécuter, ou une LoopingCommand pour exécuter un ensemble de commandes à plusieurs reprises, alors vous aurez la plupart d'un interpréteur simple.

Lorsque vous pouvez réduire un ensemble d'objets à un comportement qu'ils ont tous en commun, vous pourriez être amené à extraire une interface. En outre, vous pouvez parfois utiliser des interfaces pour empêcher les objets d'empiéter accidentellement sur les préoccupations de cette classe; pour par exemple, vous pouvez implémenter une interface qui permet uniquement aux clients de récupérer, plutôt que de modifier les données de votre objet, et que la plupart des objets ne reçoivent qu'une référence à l'interface de récupération.

Les Interfaces fonctionnent mieux lorsque vos interfaces sont relativement simples et font peu d'hypothèses.

Recherchez le principe de substitution de Liskov pour en donner plus de sens.

Certains langages statiquement typés comme C++ ne prennent pas en charge les interfaces en tant que concept de première classe, donc vous créez interfaces utilisant des classes abstraites pures.

Mise à Jour Puisque vous semblez poser des questions sur les classes abstraites par rapport aux interfaces, voici ma simplification excessive préférée:

  • les Interfaces définissent les capacités et les fonctionnalités.
  • Les classes abstraites définissent les fonctionnalités de base.

Typiquement, je fais un refactoring d'interface d'extrait avant de construire une classe abstraite. Je suis plus susceptible de construire une classe abstraite si je pense qu'il devrait y avoir un contrat de création (plus précisément, qu'un type spécifique de constructeur doit toujours être pris en charge par des sous-classes). Cependant, j'utilise rarement des classes abstraites "pures" en C#/java. Je suis beaucoup plus susceptible d'implémenter une classe avec au moins une méthode contenant un comportement significatif, et d'utiliser des méthodes abstraites pour prendre en charge les méthodes de modèle appelées par cette méthode. Ensuite, la classe abstraite est une implémentation de base d'un comportement, dont toutes les sous-classes concrètes peuvent profiter sans avoir à réimplémenter.

1
répondu JasonTrue 2008-09-23 20:29:04

Réponse Simple: une interface est un tas de signatures de méthode (+ type de retour). Quand un objet dit qu'il implémente une interface, vous savez qu'il expose cet ensemble de méthodes.

1
répondu David 2008-09-23 20:42:59

Les Interfaces sont un moyen d'implémenter les conventions d'une manière encore fortement typée et polymorphe.

Un bon exemple du monde réel serait IDisposable dans. NET. une classe qui implémente L'interface IDisposable force cette classe à implémenter la méthode Dispose (). Si la classe n'implémente pas Dispose (), Vous obtiendrez une erreur de compilateur en essayant de construire. En outre, ce modèle de code:

using (DisposableClass myClass = new DisposableClass())
  {
  // code goes here
  }

Provoquera myClass.Dispose() à exécuter automatiquement lorsque l'exécution se termine le bloc interne.

Cependant, et c'est important, il n'y a pas d'obligation à ce que votre méthode dispose() devrait faire. Vous pourriez avoir votre méthode Dispose () choisir des recettes aléatoires à partir d'un fichier et les envoyer par courriel à une liste de distribution, le compilateur ne s'en soucie pas. Le but du modèle IDisposable est de faciliter le nettoyage des ressources. Si les instances d'une classe conservent les poignées de fichiers IDisposable facilite la centralisation du code de désallocation et de nettoyage en un seul endroit et promouvoir un style d'utilisation qui garantit que la désallocation se produit toujours.

Et c'est la clé des interfaces. Ils sont un moyen de rationaliser les conventions de programmation et les modèles de conception. Ce qui, lorsqu'il est utilisé correctement, favorise un code plus simple et auto-documenté qui est plus facile à utiliser, plus facile à maintenir et plus correct.

1
répondu Wedge 2008-09-23 21:04:08

Voici un exemple lié à la base de données que j'utilise souvent. Disons que vous avez un objet et un objet conteneur, comme une liste. Supposons que parfois vous voudrez peut-être stocker les objets dans une séquence particulière. Supposons que la séquence n'est pas liée à la position dans le tableau mais que les objets sont un sous-ensemble d'un ensemble d'objets plus grand et que la position de la séquence est liée au filtrage sql de la base de données.

Pour garder une trace de vos positions de séquence personnalisées, vous pouvez faire votre objet implémente une interface personnalisée. L'interface personnalisée pourrait servir de médiateur dans l'effort organisationnel requis pour maintenir de telles séquences.

Par exemple, la séquence qui vous intéresse n'a rien à voir avec les clés primaires dans les enregistrements. Avec l'objet implémentant l'interface, vous pouvez dire myObject.suivant () ou myObject.prev().

1
répondu fooledbyprimes 2008-09-25 05:43:35

J'ai eu le même problème que vous et je trouve l'explication du "contrat" un peu déroutante.

Si vous spécifiez qu'une méthode prend une interface IEnumerable en paramètre, vous pouvez dire qu'il s'agit d'un contrat spécifiant que le paramètre doit être d'un type qui hérite de L'interface IEnumerable et supporte donc toutes les méthodes spécifiées dans l'interface IEnumerable. La même chose serait vraie si nous utilisions une classe abstraite ou une classe normale. Tout objet qui hérite de ces classes seraient ok pour passer en tant que paramètre. Vous seriez en tout cas en mesure de dire que l'objet hérité supporte toutes les méthodes publiques de la classe de base, que la classe de base soit une classe normale, une classe abstraite ou une interface.

Une classe abstraite avec toutes les méthodes abstraites est fondamentalement la même qu'une interface, donc vous pouvez dire qu'une interface est simplement une classe sans méthodes implémentées. Vous pouvez réellement supprimer les interfaces de la langue et simplement utiliser la classe abstraite avec seules les méthodes abstraites à la place. Je pense que la raison pour laquelle nous les séparons est pour des raisons sémantiques mais pour des raisons de codage, Je ne vois pas la raison et la trouve juste déroutante.

Une autre suggestion pourrait être de renommer l'interface en classe d'interface car l'interface n'est qu'une autre variante d'une classe.

Dans certaines langues, il existe des différences subtiles qui permettent à une classe d'hériter seulement de 1 classe mais de plusieurs interfaces alors que dans d'autres, vous pourriez avoir beaucoup des deux, mais c'est un autre problème et pas directement lié je pense

1
répondu terjetyl 2010-09-05 16:47:32

La façon la plus simple de comprendre les interfaces est de commencer par considérer ce que signifie l'héritage de classe. Il comprend deux aspects:

  1. les membres d'une classe dérivée peuvent utiliser les membres publics ou protégés d'une classe de base comme les leurs.
  2. les membres d'une classe dérivée peuvent être utilisés par un code qui attend un membre de la classe de base (ce qui signifie qu'ils sont substituables).

Ces deux fonctionnalités sont utiles, mais parce qu'il est difficile d'autoriser une classe à utiliser des membres de more plus d'une classe comme la sienne, de nombreux langages et frameworks ne permettent aux classes d'hériter d'une seule classe de base. D'un autre côté, il n'y a pas de difficulté particulière à ce qu'une classe soit substituable à plusieurs autres choses non liées.

De plus, parce que le premier avantage de l'héritage peut être largement atteint via l'encapsulation, l'avantage relatif de permettre l'héritage multiple du premier type est quelque peu limité. D'autre part, être capable de substituer un objet à plusieurs types de choses sans rapport est une capacité utile qui ne peut être facilement réalisée sans support linguistique.

Les Interfaces fournissent un moyen par lequel un langage / framework peut permettre aux programmes de bénéficier du deuxième aspect de l'héritage pour plusieurs types de base, sans l'obliger à fournir également le premier.

1
répondu supercat 2012-08-06 15:16:21

La plupart des interfaces que vous rencontrez sont une collection de signatures de méthodes et de propriétés. Toute personne qui implémente une interface doit fournir des définitions à ce qui est dans l'interface.

1
répondu Arcturus 2012-10-22 22:50:08

L'Interface est comme une classe entièrement abstraite. C'est-à-dire une classe abstraite avec seulement des membres abstraits. Vous pouvez également implémenter plusieurs interfaces, c'est comme hériter de plusieurs classes entièrement abstraites. De toute façon.. cette explication n'aide que si vous comprenez ce qu'est une classe abstraite.

1
répondu Raz Megrelidze 2014-07-07 05:01:56

Déplacé à cette question après cette question a été fermé comme un double, dans l'espoir que cela aidera quelqu'un:

Dans votre cas simple, vous pouvez obtenir quelque chose de similaire à ce que vous obtenez avec les interfaces en utilisant une classe de base commune qui implémente show() (ou peut-être la définit comme abstraite). Permettez-moi de changer votre nom générique pour quelque chose de plus concret, Aigle et Hawk au lieu de MyClass1 et MyClass2. Dans ce cas vous pouvez écrire du code comme

Bird bird = GetMeAnInstanceOfABird(someCriteriaForSelectingASpecificKindOfBird);
bird.Fly(Direction.South, Speed.CruisingSpeed);

, ce Qui vous permet d'écrire du code qui peut gérer tout ce que est un Oiseau. Vous pouvez alors écrire du code qui fait que Bird fait sa chose (voler, manger, pondre des œufs, etc.) qui agit sur une instance qu'il traite comme un Bird. Que le code du travail que Oiseau est vraiment un Aigle, Hawk, ou quoi que ce soit d'autre qui dérive de Oiseau.

Ce paradigme commence à devenir désordonné, cependant, quand vous n'avez pas un vrai est une relation. Dites que vous voulez écrire du code qui vole des choses dans le ciel. Si vous écrivez le code d'accepter un Oiseau classe de base, il devient d'un coup dur pour évoluer que le code fonctionne sur un JumboJet exemple, parce qu'un Oiseau et a JumboJet pouvez certainement les deux à la mouche, un JumboJet est certainement pas un Oiseau.

Entrez dans l'interface.

Ce Oiseau (et Aigle, et Hawk) Faire ont en commun est qu'ils peuvent tous voler. Si vous écrivez le code ci-dessus à la place pour agir sur une interface, IFly, ce code peut être appliqué à tout ce qui fournit une implémentation à cette interface.

0
répondu Eric J. 2017-05-23 11:54:22

Les Interfaces nécessitent que toute classe qui les implémente contienne les méthodes définies dans l'interface.

Le but est que, sans avoir à voir le code dans une classe, vous puissiez savoir s'il peut être utilisé pour une certaine tâche. Par exemple, la classe Integer en Java implémente l'interface comparable, donc, si vous ne voyez que l'en-tête de la méthode (public class String implémente Comparable), vous saurez qu'il contient une méthode compareTo ().

0
répondu cblades 2018-03-23 16:09:31