web-dev-qa-db-fra.com

Pourquoi voudrais-je utiliser des interfaces?

Je comprends qu'ils vous obligent à mettre en œuvre des méthodes et autres, mais ce que je ne peux pas comprendre, c'est pourquoi vous voudriez les utiliser. Quelqu'un peut-il me donner un bon exemple ou une explication sur la raison pour laquelle je voudrais mettre en œuvre cela.

69
user23661

n exemple spécifique: les interfaces sont un bon moyen de spécifier un contrat que le code des autres doit respecter.

Si j'écris une bibliothèque de code, je peux écrire du code qui est valide pour les objets qui ont un certain ensemble de comportements. La meilleure solution consiste à spécifier ces comportements dans une interface (pas d'implémentation, juste une description) puis à utiliser des références aux objets implémentant cette interface dans mon code de bibliothèque.

Ensuite, toute personne aléatoire peut venir, créer une classe qui implémente cette interface, instancier un objet de cette classe et le transmettre à mon code de bibliothèque et s'attendre à ce qu'il fonctionne. Remarque: il est bien sûr possible d'implémenter strictement une interface tout en ignorant l'intention de l'interface, donc la simple implémentation d'une interface n'est pas une garantie que les choses fonctionneront. Stupide trouve toujours un moyen! : -)

n autre exemple spécifique: deux équipes travaillant sur différents composants qui doivent coopérer. Si les deux équipes s'assoient le premier jour et se mettent d'accord sur un ensemble d'interfaces, elles peuvent alors se séparer et implémenter leurs composants autour de ces interfaces. L'équipe A peut créer des faisceaux de test qui simulent le composant de l'équipe B pour les tests, et vice versa. Développement parallèle et moins de bugs.

Le point clé est que les interfaces fournissent une couche de abstraction afin que vous puissiez écrire du code qui ignore les détails inutiles.

L'exemple canonique utilisé dans la plupart des manuels est celui des routines de tri. Vous pouvez trier n'importe quelle classe d'objets tant que vous avez un moyen de comparer deux des objets. Vous pouvez donc rendre n'importe quelle classe triable en implémentant l'interface IComparable, ce qui vous oblige à implémenter une méthode pour comparer deux instances. Toutes les routines de tri sont écrites pour gérer les références aux objets IComparable, donc dès que vous implémentez IComparable, vous pouvez utiliser n'importe laquelle de ces routines de tri sur les collections d'objets de votre classe.

61
Stewart Johnson

Les interfaces définissent contrats, et c'est le mot clé.

Vous utilisez une interface lorsque vous devez définir un contrat dans votre programme, mais vous ne vous souciez pas vraiment des autres propriétés de la classe qui remplit ce contrat tant qu'il le fait.

Voyons donc un exemple. Supposons que vous ayez une méthode qui fournit la fonctionnalité pour trier une liste. Première chose .. qu'est-ce qu'une liste? Vous souciez-vous vraiment des éléments qu'il contient pour trier la liste? Votre réponse devrait être non ... Dans .NET (par exemple), vous avez une interface appelée IList qui définit les opérations qu'une liste DOIT prendre en charge afin que vous ne vous souciez pas des détails réels sous la surface.

Revenons à l'exemple, vous ne connaissez pas vraiment la classe des objets dans la liste ... ni vous vous souciez. Si vous pouvez simplement comparer l'objet, vous pouvez aussi bien les trier. Vous déclarez donc un contrat:

interface IComparable
{
  // Return -1 if this is less than CompareWith
  // Return 0 if object are equal
  // Return 1 if CompareWith is less than this
  int Compare(object CompareWith);
}

ce contrat précise qu'une méthode qui accepte un objet et retourne un int doit être implémentée pour être comparable. Maintenant que vous avez défini un contrat et pour l'instant vous ne vous souciez plus de l'objet lui-même mais du contrat donc vous pouvez simplement faire:

IComparable comp1 = list.GetItem(i) as IComparable;

if (comp1.Compare(list.GetItem(i+1)) < 0)
  swapItem(list,i, i+1)

PS: Je sais que les exemples sont un peu naïfs mais ce sont des exemples ...

10
Jorge Córdoba

Un exemple typique est une architecture de plugin. Le développeur A écrit l'application principale et souhaite s'assurer que tous les plugins écrits par les développeurs B, C et D sont conformes à ce que son application attend d'eux.

9
Treb

La manière la plus simple de comprendre les interfaces est qu'elles permettent à différents objets d'exposer des fonctionnalités COMMUNES. Cela permet au programmeur d'écrire du code beaucoup plus simple et plus court qui se programme sur une interface, puis tant que les objets implémentent cette interface, cela fonctionnera.

Exemple 1: Il existe de nombreux fournisseurs de bases de données différents, MySQL, MSSQL, Oracle, etc. Cependant, tous les objets de base de données peuvent FAIRE les mêmes choses, vous trouverez donc de nombreuses interfaces pour les objets de base de données. Si un objet implémente IDBConnection, il expose les méthodes Open () et Close (). Donc, si je veux que mon programme soit indépendant du fournisseur de base de données, je programme à l'interface et non aux fournisseurs spécifiques.

IDbConnection connection = GetDatabaseConnectionFromConfig()
connection.Open()
// do stuff
connection.Close()

Voir en programmant sur une interface (IDbconnection) Je peux maintenant échanger n'importe quel fournisseur de données dans ma configuration mais mon code reste exactement le même. Cette flexibilité peut être extrêmement utile et facile à maintenir. L'inconvénient est que je ne peux effectuer que des opérations de base de données `` génériques '' et que je ne peux pas utiliser pleinement la force offerte par chaque fournisseur en particulier, car avec tout dans la programmation, vous avez un compromis et vous devez déterminer quel scénario vous bénéficiera le plus.

Exemple 2: Si vous remarquez que presque toutes les collections implémentent cette interface appelée IEnumerable. IEnumerable renvoie un IEnumerator qui a MoveNext (), Current et Reset (). Cela permet à C # de se déplacer facilement dans votre collection. La raison pour laquelle il peut le faire est qu'il expose l'interface IEnumerable qu'il SAIT que l'objet expose les méthodes dont il a besoin pour le parcourir. Cela fait deux choses. 1) les boucles foreach sauront désormais comment énumérer la collection et 2) vous pouvez désormais appliquer de puissantes expressions LINQ à votre collection. Encore une fois, la raison pour laquelle les interfaces sont si utiles ici est que toutes les collections ont quelque chose en COMMUN, elles peuvent être déplacées. Chaque collection peut être déplacée d'une manière différente (liste liée vs tableau), mais c'est la beauté des interfaces que l'implémentation est cachée et non pertinente pour le consommateur de l'interface. MoveNext () vous donne l'élément suivant dans la collection, peu importe COMMENT il le fait. Assez sympa, hein?

Exemple 3: Lorsque vous concevez vos propres interfaces, il vous suffit de vous poser une question. Qu'est-ce que ces choses ont en commun? Une fois que vous avez trouvé tout ce que les objets partagent, vous résumez ces propriétés/méthodes dans une interface afin que chaque objet puisse en hériter. Ensuite, vous pouvez programmer contre plusieurs objets à l'aide d'une seule interface.

Et bien sûr, je dois donner mon exemple polymorphe C++ préféré, l'exemple des animaux. Tous les animaux partagent certaines caractéristiques. Disons qu'ils peuvent se déplacer, parler et qu'ils ont tous un nom. Depuis que je viens d'identifier ce que tous mes animaux ont en commun et je peux résumer ces qualités dans l'interface IAnimal. Ensuite, je crée un objet Bear, un objet Owl et un objet Snake implémentant tous cette interface. La raison pour laquelle vous pouvez stocker différents objets ensemble qui implémentent la même interface est que les interfaces représentent une réplication IS-A. Un ours IS-A animal, un hibou IS-A animal, donc ça fait depuis que je peux tous les collectionner en tant qu'animaux.

var animals = new IAnimal[] = {new Bear(), new Owl(), new Snake()} // here I can collect different objects in a single collection because they inherit from the same interface

foreach (IAnimal animal in animals) 
{
    Console.WriteLine(animal.Name)
    animal.Speak() // a bear growls, a owl hoots, and a snake hisses
    animal.Move() // bear runs, owl flys, snake slithers
}

Vous pouvez voir que même si ces animaux effectuent chaque action d'une manière différente, je peux les programmer contre tous dans un modèle unifié et ce n'est là qu'un des nombreux avantages des interfaces.

Encore une fois, la chose la plus importante avec les interfaces est ce que les objets ont en commun pour que vous puissiez programmer contre DIFFÉRENTS objets de la même manière. Gagne du temps, crée des applications plus flexibles, masque la complexité/implémentation, modélise des objets/situations du monde réel, parmi de nombreux autres avantages.

J'espère que cela t'aides.

8
Despertar

Les pédales d'une voiture implémentent une interface. Je viens des États-Unis où nous roulons sur le côté droit de la route. Nos volants sont sur le côté gauche de la voiture. Les pédales pour une transmission manuelle de gauche à droite sont embrayage -> frein -> accélérateur. Quand je suis allé en Irlande, la conduite est inversée. Les volants des voitures sont à droite et ils roulent sur le côté gauche de la route ... mais les pédales, ah les pédales ... ils ont mis en œuvre la même interface ... les trois pédales étaient dans le même ordre ... donc même si la classe était différente et le réseau sur lequel la classe fonctionnait était différent, j'étais toujours à l'aise avec l'interface de la pédale. Mon cerveau a pu appeler mes muscles sur cette voiture comme toutes les autres voitures.

Pensez aux nombreuses interfaces sans programmation sans lesquelles nous ne pouvons pas vivre. Répondez ensuite à votre propre question.

5
Mark Brady

Les interfaces sont absolument nécessaires dans un système orienté objet qui s'attend à faire bon usage du polymorphisme.

Un exemple classique pourrait être IVehicle, qui a une méthode Move (). Vous pourriez avoir des classes Car, Bike et Tank, qui implémentent IVehicle. Ils peuvent tous Move (), et vous pouvez écrire du code qui ne se souciait pas de quel type de véhicule il s'agissait, juste pour qu'il puisse Move ().

void MoveAVehicle(IVehicle vehicle)
{
    vehicle.Move();
}
4
Eric Z Beard
When you need different classes to share same methods you use Interfaces.
4
Lev

Les interfaces sont une forme de polymorphisme. Un exemple:

Supposons que vous souhaitiez écrire du code de journalisation. La journalisation va aller quelque part (peut-être vers un fichier ou un port série sur l'appareil sur lequel le code principal s'exécute, ou vers un socket, ou jeté comme/dev/null). Vous ne savez pas où: l'utilisateur de votre code de journalisation doit être libre de le déterminer. En fait, votre code de journalisation s'en moque. Il veut juste quelque chose sur lequel il peut écrire des octets.

Ainsi, vous inventez une interface appelée "quelque chose sur laquelle vous pouvez écrire des octets". Le code de journalisation reçoit une instance de cette interface (peut-être au moment de l'exécution, peut-être qu'il est configuré au moment de la compilation. C'est toujours du polymorphisme, juste des types différents). Vous écrivez une ou plusieurs classes implémentant l'interface, et vous pouvez facilement changer où va la journalisation simplement en changeant celle que le code de journalisation utilisera. Quelqu'un d'autre peut changer où va la journalisation en écrivant ses propres implémentations de l'interface, sans changer votre code. C'est essentiellement ce à quoi correspond le polymorphisme - en savoir juste assez sur un objet pour l'utiliser d'une manière particulière, tout en lui permettant de varier à tous égards que vous n'avez pas besoin de connaître. Une interface décrit les choses que vous devez savoir.

Les descripteurs de fichiers de C sont essentiellement une interface "quelque chose que je peux lire et/ou écrire des octets depuis et/ou vers", et presque tous les langages typés ont de telles interfaces qui se cachent dans ses bibliothèques standard: des flux ou autres. Les langues non typées ont généralement des types informels (peut-être appelés contrats) qui représentent des flux. Donc, dans la pratique, vous n'avez presque jamais à inventer vous-même cette interface particulière: vous utilisez ce que le langage vous donne.

La journalisation et les flux ne sont qu'un exemple - les interfaces se produisent chaque fois que vous pouvez décrire en termes abstraits ce qu'un objet est censé faire, mais ne voulez pas le lier à une implémentation/classe/autre.

3
Steve Jessop

Il y a plusieurs raisons de le faire. Lorsque vous utilisez une interface, vous êtes prêt à l'avenir lorsque vous aurez besoin de refactoriser/réécrire le code. Vous pouvez également fournir une sorte d'API standardisée pour des opérations simples.

Par exemple, si vous voulez écrire un algorithme de tri comme le tri rapide, tout ce dont vous avez besoin pour trier n'importe quelle liste d'objets est que vous pouvez comparer avec succès deux des objets. Si vous créez une interface, par exemple ISortable, quiconque crée des objets peut implémenter l'interface ISortable et utiliser votre code de tri.

Si vous écrivez du code qui utilise un stockage de base de données et que vous écrivez dans une interface de stockage, vous pouvez remplacer ce code sur toute la ligne.

Les interfaces encouragent un couplage plus lâche de votre code afin que vous puissiez avoir une plus grande flexibilité.

2
Douglas Mayle

Imaginez l'interface de base suivante qui définit un mécanisme CRUD de base:

interface Storable {
    function create($data);
    function read($id);
    function update($data, $id);
    function delete($id);
}

Depuis cette interface, vous pouvez dire que tout objet qui l'implémente doit avoir des fonctionnalités pour créer, lire, mettre à jour et supprimer des données. Cela pourrait être par une connexion à une base de données, un lecteur de fichiers CSV et un lecteur de fichiers XML, ou tout autre type de mécanisme qui pourrait vouloir utiliser des opérations CRUD.

Ainsi, vous pouvez maintenant avoir quelque chose comme ceci:

class Logger {
    Storable storage;

    function Logger(Storable storage) {
        this.storage = storage;
    }

    function writeLogEntry() {
        this.storage.create("I am a log entry");
    }
}

Cet enregistreur ne se soucie pas si vous passez une connexion à une base de données ou quelque chose qui manipule des fichiers sur le disque. Tout ce qu'il doit savoir, c'est qu'il peut appeler create () dessus, et cela fonctionnera comme prévu.

La question suivante qui se pose alors est que si les bases de données et les fichiers CSV, etc., peuvent tous stocker des données, ne devraient-elles pas être héritées d'un objet générique Storable et ainsi supprimer le besoin d'interfaces? La réponse à cette question est non ... toutes les connexions à la base de données ne peuvent pas implémenter les opérations CRUD, et il en va de même pour tous les lecteurs de fichiers.

Les interfaces définissent ce que l'objet est capable de faire et comment vous devez l'utiliser ... pas ce qu'il est!

2
JamShady

Comme vous l'avez noté, les interfaces sont bonnes lorsque vous voulez forcer quelqu'un à le faire dans un certain format.

Les interfaces sont bonnes lorsque les données qui ne sont pas dans un certain format peuvent signifier faire des hypothèses dangereuses dans votre code.

Par exemple, en ce moment j'écris une application qui transformera les données d'un format dans un autre. Je veux les forcer à placer ces champs, donc je sais ils existeront et auront plus de chances d'être correctement mis en œuvre. Je m'en fiche si une autre version sort et qu'elle ne se compile pas pour eux car il est plus probable que des données soient de toute façon nécessaires.

Les interfaces sont rarement utilisées à cause de cela, car généralement vous pouvez faire des hypothèses ou ne pas vraiment exiger les données pour faire ce que vous devez faire.

1
Kenny Mann

Une interface, définit simplement interface. Plus tard, vous pouvez définir une méthode (sur d'autres classes), qui accepte les interfaces comme paramètres (ou plus précisément, un objet qui implémente cette interface). De cette façon, votre méthode peut fonctionner sur une grande variété d'objets, dont le seul point commun est qu'ils implémentent cette interface.

1
James Curran

Tout d'abord, ils vous donnent un couche d'abstraction supplémentaire. Vous pouvez dire "Pour cette fonction, ce paramètre doit être un objet qui a ces méthodes avec ces paramètres". Et vous voudrez probablement également définir la signification de ces méthodes, en termes quelque peu abstraits, tout en vous permettant de raisonner sur le code. En typé canard langues vous obtenez cela gratuitement. Pas besoin d'interfaces de syntaxe explicites. Pourtant, vous créez probablement encore un ensemble de interfaces conceptuelles, quelque chose comme des contrats (comme dans Design by Contract).

De plus, les interfaces sont parfois utilisées à des fins moins "pures". En Java, ils peuvent être utilisés pour émuler l'héritage multiple. En C++, vous pouvez les utiliser pour réduire les temps de compilation.

En général, ils réduisent le couplage dans votre code. C'est une bonne chose.

Votre code peut également être plus facile à tester de cette façon.

1
Paweł Hajdan

Disons que vous voulez garder une trace d'une collection de choses. Ces collections doivent prendre en charge un tas de choses, comme l'ajout et la suppression d'éléments, et la vérification si un élément se trouve dans la collection.

Vous pouvez ensuite spécifier une interface ICollection avec les méthodes add (), remove () et contains ().

Code qui n'a pas besoin de savoir quel type de collection (List, Array, Hash-table, Red-black tree, etc.) pourrait accepter des objets qui ont implémenté l'interface et travailler avec eux sans connaître leur type réel.

1
jakber

Dans .Net, je crée des classes de base et en hérite lorsque les classes sont en quelque sorte liées. Par exemple, la classe de base Person peut être héritée par Employee et Customer. La personne peut avoir des propriétés communes comme les champs d'adresse, le nom, le téléphone, etc. L'employé peut avoir sa propre propriété de service. Le client a d'autres propriétés exclusives.

Puisqu'une classe ne peut hériter que d'une autre classe dans .Net, j'utilise des interfaces pour des fonctionnalités partagées supplémentaires. Parfois, les interfaces sont partagées par des classes qui ne sont autrement pas liées. L'utilisation d'une interface crée un contrat dont les développeurs sauront qu'il est partagé par toutes les autres classes qui l'implémentent. Je force également ces classes à implémenter tous ses membres.

1
DOK

Dans un article de mon blog, je décris brièvement trois objectifs des interfaces.

Les interfaces peuvent avoir différentes finalités:

  • Fournissez différentes implémentations pour le même objectif. L'exemple typique est une liste, qui peut avoir différentes implémentations pour différents cas d'utilisation de performances (LinkedList, ArrayList, etc.).
  • Autoriser la modification des critères. Par exemple, une fonction de tri peut accepter une interface comparable afin de fournir tout type de critère de tri, basé sur le même algorithme.
  • Masquer les détails de l'implémentation. Cela facilite également la lecture des commentaires par un utilisateur, car dans le corps de l'interface, il n'y a que des méthodes, des champs et des commentaires, pas de longs morceaux de code à ignorer.

Voici le texte intégral de l'article: http://weblogs.manas.com.ar/ary/2007/11/

1
asterite

Il existe plusieurs autres réponses à une question similaire ici: Interface vs Base Class

1
razlebe

Le meilleur code Java Java que j'ai jamais vu défini presque toutes les références d'objet comme des instances d'interfaces au lieu d'instances de classes. C'est un signe fort de code de qualité conçu pour la flexibilité et le changement.

1
dongilmore

Je pense que vous devez avoir une bonne compréhension des modèles de conception, alors voyez la puissance.

Découvrez Head First Design Patterns

1
None

En C #, les interfaces sont également extrêmement utiles pour permettre le polymorphisme pour les classes qui ne partagent pas les mêmes classes de base. Cela signifie que, comme nous ne pouvons pas avoir d'héritage multiple, vous pouvez utiliser des interfaces pour autoriser l'utilisation de différents types. C'est également un moyen de vous permettre d'exposer des membres privés pour une utilisation sans réflexion (implémentation explicite), donc cela peut être un bon moyen d'implémenter des fonctionnalités tout en gardant votre modèle d'objet propre.

Par exemple:

public interface IExample
{
    void Foo();
}

public class Example : IExample
{
    // explicit implementation syntax
    void IExample.Foo() { ... }
}

/* Usage */
Example e = new Example();

e.Foo(); // error, Foo does not exist

((IExample)e).Foo(); // success
1
justin.m.chase