Que signifie “programmer sur une interface”?

J’ai vu cela mentionné à quelques resockets et je ne sais pas ce que cela signifie. Quand et pourquoi le feriez-vous?

Je sais ce que font les interfaces, mais le fait que je ne sois pas clair à ce sujet me fait penser que je ne les utilise pas correctement.

Est-ce que c’est juste si vous deviez faire:

IInterface classRef = new ObjectWhatever() 

Vous pouvez utiliser n’importe quelle classe qui implémente IInterface ? Quand auriez-vous besoin de faire cela? La seule chose à laquelle je peux penser, c’est si vous avez une méthode et que vous n’êtes pas sûr de quel object sera transmis, attendez-vous à l’implémentation de IInterface . Je ne peux pas penser à quelle fréquence vous auriez besoin de le faire … (Aussi, comment pourriez-vous écrire une méthode qui intègre un object qui implémente une interface? Est-ce possible?)

Désolé si j’ai complètement raté le point.

Il y a ici des réponses merveilleuses à ces questions qui contiennent toutes sortes de détails sur les interfaces et le code de couplage libre, l’inversion du contrôle, etc. Il y a des discussions assez compliquées, alors j’aimerais profiter de l’occasion pour comprendre un peu pourquoi une interface est utile.

Lorsque j’ai commencé à être exposé à des interfaces, j’étais également confus quant à leur pertinence. Je n’ai pas compris pourquoi tu en avais besoin. Si nous utilisons un langage comme Java ou C #, nous avons déjà l’inheritance et j’ai vu les interfaces comme une forme d’inheritance plus faible et j’ai pensé: “Pourquoi s’embêter?” En un sens, j’avais raison, vous pouvez considérer les interfaces comme une sorte d’inheritance faible, mais au-delà, j’ai finalement compris leur utilisation comme une construction de langage en les considérant comme un moyen de classer des traits ou des comportements communs. potentiellement plusieurs classes d’objects non liés.

Par exemple – disons que vous avez un jeu SIM et que vous avez les classes suivantes:

  class HouseFly inherits Insect { void FlyAroundYourHead(){} void LandOnThings(){} } class Telemarketer inherits Person { void CallDuringDinner(){} void ContinueTalkingWhenYouSayNo(){} } 

Clairement, ces deux objects n’ont rien en commun en termes d’inheritance direct. Mais, vous pourriez dire qu’ils sont tous les deux ennuyeux.

Disons que notre jeu doit avoir une sorte de truc au hasard qui agace le joueur lorsqu’il dîne. Cela pourrait être un HouseFly ou un Telemarketer ou les deux – mais comment pouvez-vous prévoir les deux avec une seule fonction? Et comment demandez-vous à chaque type d’object de “faire leur truc gênant” de la même manière?

La clé pour se rendre compte est qu’un Telemarketer et HouseFly partagent un comportement communément interprété, même s’ils ne se ressemblent pas en termes de modélisation. Faisons donc une interface que les deux peuvent implémenter:

  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 être ennuyeuses à leur manière. Et ils n’ont pas besoin de dériver de la même classe de base et de partager des caractéristiques inhérentes communes – ils doivent simplement satisfaire le contrat d’ IPest – ce contrat est simple. Vous devez juste BeAnnoying . À cet égard, nous pouvons modéliser ce qui suit:

  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 certain nombre de convives et un certain nombre de parasites – notez l’utilisation de l’interface. Cela signifie que dans notre petit monde, un membre du tableau des pests pourrait en réalité être un object Telemarketer ou un object HouseFly .

La méthode ServeDinner est appelée lorsque le dîner est servi et que nos employés de la salle à manger sont censés manger. Dans notre petit jeu, c’est à ce moment-là que nos ravageurs font leur travail – chaque parasite est IPest interface IPest . De cette façon, nous pouvons facilement faire en sorte que les Telemarketers et HouseFlys chacun à leur façon – nous nous préoccupons uniquement de l’object de DiningRoom qui est nuisible, nous ne nous soucions pas vraiment de ce qu’il est et ils pourraient n’a rien de commun avec les autres.

Cet exemple de pseudo-code très artificiel (qui traînait beaucoup plus longtemps que prévu) a simplement pour but d’illustrer le genre de chose qui a finalement allumé la lumière pour moi lorsque nous utilisions une interface. Je m’excuse d’avance pour la bêtise de l’exemple, mais j’espère que cela vous aidera à comprendre. Et, bien sûr, les autres réponses que vous avez reçues ici couvrent toute la gamme des interfaces utilisées aujourd’hui dans les modèles de conception et les méthodologies de développement.

L’exemple spécifique que je donnais 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 

Celles-ci sont identiques dans un programme court, mais si vous utilisez myList 100 fois dans votre programme, vous pouvez commencer à voir une différence. La première déclaration garantit que vous appelez uniquement les méthodes de myList définies par l’interface List (donc aucune méthode spécifique à ArrayList ). Si vous avez programmé l’interface de cette façon, vous pourrez décider ultérieurement de

 List myList = new TreeList(); 

et vous n’avez qu’à changer votre code à cet endroit. Vous savez déjà que le rest de votre code ne fait rien qui soit cassé en modifiant l’ implémentation car vous avez programmé vers l’ interface .

Les avantages sont encore plus évidents (je pense) lorsque vous parlez de parameters de méthode et de valeurs de retour. Prenons par exemple ceci:

 public ArrayList doSomething(HashMap map); 

Cette déclaration de méthode vous lie à deux implémentations concrètes ( ArrayList et HashMap ). Dès que cette méthode est appelée depuis un autre code, toute modification apscope à ces types signifie probablement que vous devrez également modifier le code d’appel. Il serait préférable de programmer sur les interfaces.

 public List doSomething(Map map); 

Peu importe le type de List vous retournez, ou quel type de Map est passé en paramètre. Les modifications que vous apportez à la méthode doSomething ne vous obligeront pas à modifier le code d’appel.

Programmation à une interface dit: “J’ai besoin de cette fonctionnalité et je ne me soucie pas de savoir d’où elle vient.”

Considérez (en Java), l’interface List par rapport aux classes concrètes ArrayList et LinkedList . Si tout ce qui m’importe, c’est d’avoir une structure de données contenant plusieurs éléments de données auxquels je devrais accéder via une itération, je choisirais une List (et cela représente 99% du temps). Si je sais que j’ai besoin d’insérer / supprimer en permanence des deux côtés de la liste, je pourrais choisir l’implémentation concrète de LinkedList (ou, plus probablement, utiliser l’interface de queue ). Si je sais que j’ai besoin d’un access aléatoire par index, je choisirais la classe concrète ArrayList .

L’utilisation d’interfaces est un facteur clé pour rendre votre code facilement testable en plus de supprimer les couplages inutiles entre vos classes. En créant une interface qui définit les opérations sur votre classe, vous autorisez les classes qui souhaitent utiliser cette fonctionnalité à l’utiliser sans dépendre directement de votre classe d’implémentation. Si vous décidez ultérieurement de modifier et d’utiliser une implémentation différente, vous devez uniquement modifier la partie du code où l’implémentation est instanciée. Le rest du code n’a pas besoin d’être modifié car il dépend de l’interface et non de la classe d’implémentation.

Ceci est très utile pour créer des tests unitaires. Dans la classe testée, vous dépendez de l’interface et injectez une instance de l’interface dans la classe (ou une fabrique qui lui permet de créer des instances de l’interface selon les besoins) via le constructeur ou un paramètre de propriété. La classe utilise l’interface fournie (ou créée) dans ses méthodes. Lorsque vous allez écrire vos tests, vous pouvez simuler ou simuler l’interface et fournir une interface qui répond aux données configurées dans votre test unitaire. Vous pouvez le faire car votre classe testée ne traite que de l’interface, pas de votre implémentation concrète. Toute classe implémentant l’interface, y compris votre classe simulée ou fausse, fera l’affaire.

EDIT: Ci-dessous, un lien vers un article où Erich Gamma discute de sa citation, “Programme à une interface, pas à une implémentation”.

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

Vous devriez regarder dans l’inversion du contrôle:

  • Martin Fowler: Inversion des conteneurs de contrôle et modèle d’dependency injection
  • Wikipedia: Inversion du contrôle

Dans un tel scénario, vous n’écririez pas ceci:

 IInterface classRef = new ObjectWhatever(); 

Vous écririez quelque chose comme ceci:

 IInterface classRef = container.Resolve(); 

Cela entrerait dans une configuration basée sur des règles dans l’object container et créerait l’object réel pour vous, qui pourrait être ObjectWhatever. L’important est que vous puissiez remplacer cette règle par quelque chose qui utilise un autre type d’object, et votre code fonctionnera toujours.

Si nous laissons l’IoC hors de la table, vous pouvez écrire du code qui sait qu’il peut communiquer avec un object qui fait quelque chose de spécifique , mais pas quel type d’object ou comment il le fait.

Cela serait pratique lors du passage de parameters.

En ce qui concerne votre question entre parenthèses, “Comment pouvez-vous également écrire une méthode qui intègre un object implémentant une interface? Est-ce possible?”, En C #, vous utiliseriez simplement le type d’interface pour le type de paramètre, comme ceci:

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

Cela se twig directement sur le “parler à un object qui fait quelque chose de spécifique”. La méthode définie ci-dessus sait à quoi s’attendre de l’object, qu’elle implémente tout dans IInterface, mais peu importe le type d’object, mais seulement qu’il adhère au contrat, ce qui est ce qu’est une interface.

Par exemple, vous êtes probablement familier avec les calculasortingces et vous en avez probablement utilisé plusieurs à vos jours, mais la plupart du temps elles sont toutes différentes. En revanche, vous savez comment une calculasortingce standard devrait fonctionner, vous pouvez donc tous les utiliser, même si vous ne pouvez pas utiliser les fonctionnalités spécifiques de chaque calculasortingce.

C’est la beauté des interfaces. Vous pouvez écrire un morceau de code, qui sait qu’il va recevoir des objects auxquels il peut s’attendre d’un certain comportement. Il ne se soucie pas de savoir quel type d’object c’est, mais seulement qu’il supporte le comportement requirejs.

Laissez-moi vous donner un exemple concret.

Nous avons un système de traduction sur mesure pour les formulaires Windows. Ce système parcourt les contrôles d’un formulaire et traduit le texte dans chacun d’eux. Le système sait comment gérer les commandes de base, comme la propriété-type-de-contrôle-que-a-un-texte-texte, et des trucs de base similaires, mais pour tout élément de base, il ne répond pas.

Maintenant, puisque les contrôles héritent des classes prédéfinies sur lesquelles nous n’avons aucun contrôle, nous pouvons faire l’une des trois choses suivantes:

  1. Créer un support pour notre système de traduction afin de détecter spécifiquement le type de contrôle avec lequel il travaille et de traduire les bons bits (cauchemar de maintenance)
  2. Construire le support en classes de base (impossible, puisque tous les contrôles héritent de différentes classes prédéfinies)
  3. Ajouter un support d’interface

Donc nous avons fait nr. 3. Tous nos contrôles implémentent ILocalizable, une interface qui nous donne une méthode, la possibilité de se “traduire” dans un conteneur de texte / règles de traduction. En tant que tel, le formulaire n’a pas besoin de savoir quel type de contrôle il a trouvé, seulement qu’il implémente l’interface spécifique, et sait qu’il existe une méthode où il peut appeler pour localiser le contrôle.

La programmation à une interface n’a absolument rien à voir avec les interfaces abstraites comme on le voit en Java ou en .NET. Ce n’est même pas un concept de POO.

Ce que cela signifie vraiment, c’est de ne pas jouer avec les composants internes d’un object ou d’une structure de données. Utilisez l’interface de programme abstraite, ou API, pour interagir avec vos données. En Java ou en C #, cela signifie utiliser des propriétés et des méthodes publiques au lieu de l’access aux champs bruts. Pour C, cela signifie utiliser des fonctions au lieu de pointeurs bruts.

EDIT: Et avec les bases de données, cela signifie utiliser des vues et des procédures stockées au lieu d’un access direct à la table.

Code vers l’interface Pas la mise en œuvre n’a rien à voir avec Java, ni sa construction d’interface.

Ce concept a été mis en évidence dans les livres Patterns / Gang of Four, mais était très probablement bien avant cela. Le concept existait certainement bien avant que Java n’ait jamais existé.

La construction de l’interface Java a été créée pour faciliter cette idée (entre autres choses) et les personnes sont devenues trop centrées sur la construction en tant que centre de la signification plutôt que sur l’intention originale. Cependant, c’est la raison pour laquelle nous avons des méthodes et des atsortingbuts publics et privés en Java, C ++, C #, etc.

Cela signifie qu’il suffit d’interagir avec un object ou l’interface publique du système. Ne vous inquiétez pas ou même prévoyez comment il fait ce qu’il fait en interne. Ne vous inquiétez pas de la façon dont il est implémenté. Dans le code orienté object, c’est pourquoi nous avons des méthodes / atsortingbuts publics vs privés. Nous sums censés utiliser les méthodes publiques car les méthodes privées ne sont utilisées qu’en interne, au sein de la classe. Ils constituent l’implémentation de la classe et peuvent être modifiés si nécessaire sans modifier l’interface publique. Supposons qu’en ce qui concerne la fonctionnalité, une méthode sur une classe exécute la même opération avec le même résultat attendu chaque fois que vous l’appelez avec les mêmes parameters. Cela permet à l’auteur de changer le fonctionnement de la classe, son implémentation, sans casser la manière dont les gens interagissent avec elle.

Et vous pouvez programmer à l’interface, pas l’implémentation sans jamais utiliser une construction d’interface. Vous pouvez programmer à l’interface pas l’implémentation en C ++, qui n’a pas de construction d’interface. Vous pouvez intégrer deux systèmes d’entreprise massifs de manière beaucoup plus robuste tant qu’ils interagissent via des interfaces publiques (contrats) plutôt que d’appeler des méthodes sur des objects internes aux systèmes. Les interfaces doivent toujours réagir de la même manière, étant donné les mêmes parameters d’entrée; si implémenté à l’interface et non à l’implémentation. Le concept fonctionne dans de nombreux endroits.

Secouez la pensée que les interfaces Java ont quelque chose à voir avec le concept de «programme à l’interface, pas l’implémentation». Ils peuvent aider à appliquer le concept, mais ils ne sont pas le concept.

Il semble que vous compreniez le fonctionnement des interfaces, mais vous ne savez pas quand les utiliser et quels sont leurs avantages. Voici quelques exemples de cas où une interface aurait du sens:

 // if I want to add search capabilities to my application and support multiple search // engines such as google, yahoo, live, etc. interface ISearchProvider { ssortingng Search(ssortingng keywords); } 

alors je pourrais créer GoogleSearchProvider, YahooSearchProvider, LiveSearchProvider etc.

 // if I want to support multiple downloads using different protocols // HTTP, HTTPS, FTP, FTPS, etc. interface IUrlDownload { void Download(ssortingng url) } // how about an image loader for different kinds of images JPG, GIF, PNG, etc. interface IImageLoader { Bitmap LoadImage(ssortingng filename) } 

puis créez JpegImageLoader, GifImageLoader, PngImageLoader, etc.

La plupart des compléments et systèmes de plug-ins fonctionnent avec des interfaces.

Une autre utilisation populaire concerne le modèle de référentiel. Disons que je veux charger une liste de codes postaux de différentes sources

 interface IZipCodeRepository { IList GetZipCodes(ssortingng state); } 

alors je pourrais créer un XMLZipCodeRepository, SQLZipCodeRepository, CSVZipCodeRepository, etc. Pour mes applications Web, je crée souvent des référentiels XML très tôt pour que je puisse faire fonctionner quelque chose avant que la firebase database SQL soit prête. Une fois la firebase database prête, j’écris un SQLRepository pour remplacer la version XML. Le rest de mon code rest inchangé puisqu’il s’exécute seul des interfaces.

Les méthodes peuvent accepter des interfaces telles que:

 PrintZipCodes(IZipCodeRepository zipCodeRepository, ssortingng state) { foreach (ZipCode zipCode in zipCodeRepository.GetZipCodes(state)) { Console.WriteLine(zipCode.ToSsortingng()); } } 

Cela rend votre code beaucoup plus extensible et plus facile à gérer lorsque vous avez des ensembles de classes similaires. Je suis un programmeur junior, donc je ne suis pas un expert, mais je viens de terminer un projet qui nécessitait quelque chose de similaire.

Je travaille sur un logiciel côté client qui communique avec un serveur exécutant un appareil médical. Nous développons une nouvelle version de cet appareil avec de nouveaux composants que le client doit parfois configurer. Il existe deux types de nouveaux composants, et ils sont différents, mais ils sont également très similaires. Fondamentalement, je devais créer deux formulaires de configuration, deux classes de listes, deux de tout.

J’ai décidé qu’il serait préférable de créer une classe de base abstraite pour chaque type de contrôle qui contiendrait presque toute la logique réelle, puis des types dérivés pour prendre en compte les différences entre les deux composants. Cependant, les classes de base n’auraient pas été en mesure d’effectuer des opérations sur ces composants si je devais me soucier des types tout le temps (eh bien, ils auraient pu, mais il y aurait eu une instruction “if” ou une méthode) .

J’ai défini une interface simple pour ces composants et toutes les classes de base communiquent avec cette interface. Maintenant, quand je change quelque chose, ça fonctionne plutôt bien partout et je n’ai pas de duplication de code.

Si vous programmez en Java, JDBC est un bon exemple. JDBC définit un ensemble d’interfaces mais ne dit rien sur l’implémentation. Vos applications peuvent être écrites sur cet ensemble d’interfaces. En théorie, vous choisissez un pilote JDBC et votre application fonctionnera simplement. Si vous découvrez qu’il existe un pilote JDBC plus rapide ou «meilleur» ou moins cher ou pour une raison quelconque, vous pouvez en principe reconfigurer votre fichier de propriétés, et sans avoir à modifier votre application, votre application fonctionnera toujours.

La programmation en interfaces est géniale, elle favorise un couplage lâche. Comme @lassevk l’a mentionné, Inversion of Control est un bon usage de ceci.

En outre, examinez les principes SOLID . voici une série de vidéos

Il passe par un code dur (exemple fortement couplé) puis examine les interfaces, pour finalement aboutir à un outil IoC / DI (NInject).

En plus de la réponse déjà sélectionnée (et des différentes publications informatives ici), je vous recommande vivement de vous procurer une copie de Head First Design Patterns . C’est une lecture très facile qui répondra directement à votre question, expliquera pourquoi elle est importante et vous montrera de nombreux schémas de programmation que vous pouvez utiliser pour utiliser ce principe (et d’autres).

Beaucoup d’explications, mais pour le rendre encore plus simple. Prenons par exemple une List . On peut implémenter une liste avec comme:

  1. un tableau interne
  2. Une liste liée
  3. autre mise en œuvre

En créant une interface, dites une List . Vous ne codez que pour la définition de Liste ou de ce que List signifie en réalité.

Vous pouvez utiliser n’importe quel type d’implémentation en interne, par exemple une implémentation de array . Mais supposons que vous souhaitiez modifier l’implémentation pour une raison quelconque, par exemple un bogue ou une performance. Il vous suffit ensuite de changer la List ls = new ArrayList() déclaration List ls = new ArrayList() en List ls = new LinkedList() .

Non, où d’autre dans le code, devrez-vous changer autre chose? Parce que tout le rest a été construit sur la définition de la List .

Je suis un nouveau venu à cette question, mais je tiens à mentionner ici que la ligne “Programmer une interface, pas une implémentation” a fait l’object de bonnes discussions dans le livre de GoF (Gang of Four) Design Patterns.

Il a déclaré, à la p. 18:

Programme à une interface, pas une implémentation

Ne déclarez pas les variables comme des instances de classes concrètes particulières. Au lieu de cela, ne validez que sur une interface définie par une classe abstraite. Vous trouverez que ceci est un thème commun des modèles de conception dans ce livre.

et surtout, cela a commencé avec:

Il y a deux avantages à manipuler des objects uniquement en termes d’interface définie par les classes abstraites:

  1. Les clients ne connaissent pas les types d’objects spécifiques qu’ils utilisent, à condition que les objects adhèrent à l’interface attendue par les clients.
  2. Les clients ne connaissent pas les classes qui implémentent ces objects. Les clients ne connaissent que la ou les classes abstraites définissant l’interface.

En d’autres termes, n’écrivez pas vos classes de manière à ce qu’elles quack() une méthode quack() pour les canards, puis une méthode bark() pour les chiens, car elles sont trop spécifiques pour une implémentation particulière d’une classe (ou d’une sous-classe). . Au lieu de cela, écrivez la méthode en utilisant des noms suffisamment généraux pour être utilisés dans la classe de base, tels que giveSound() ou move() , afin qu’ils puissent être utilisés pour les canards, les chiens ou même les voitures, puis le client de votre Les classes peuvent simplement dire .giveSound() plutôt que de penser à utiliser quack() ou bark() ou même à déterminer le type avant d’émettre le message correct à envoyer à l’object.

Pour append aux publications existantes, le codage des interfaces aide parfois les grands projets lorsque les développeurs travaillent simultanément sur des composants distincts. Tout ce dont vous avez besoin est de définir des interfaces en amont et de leur écrire du code pendant que d’autres développeurs écrivent du code sur l’interface que vous implémentez.

C’est aussi bon pour les tests unitaires, vous pouvez injecter vos propres classes (qui répondent aux exigences de l’interface) dans une classe qui en dépend

Donc, juste pour bien comprendre, l’avantage d’une interface est que je peux séparer l’appel d’une méthode de n’importe quelle classe particulière. Au lieu de cela, créer une instance de l’interface, où l’implémentation est donnée à partir de la classe que je choisis qui implémente cette interface. Cela me permet donc d’avoir beaucoup de classes, qui ont des fonctionnalités similaires mais légèrement différentes et dans certains cas (les cas liés à l’intention de l’interface) ne se soucient pas de l’object.

Par exemple, je pourrais avoir une interface de mouvement. Une méthode qui fait «bouger» quelque chose et tout object (personne, voiture, chat) qui implémente l’interface de mouvement peut être transmis et dit de bouger. Sans la méthode, tout le monde connaît le type de classe.

Imaginez que vous ayez un produit appelé «Zebra» qui peut être étendu par des plugins. Il trouve les plugins en recherchant des DLL dans un répertoire. Il charge toutes ces DLL et utilise la reflection pour trouver les classes qui implémentent IZebraPlugin , puis appelle les méthodes de cette interface pour communiquer avec les plug-ins.

Cela le rend complètement indépendant de toute classe de plug-in spécifique – peu importe la classe. Ils ne se soucient que de répondre aux spécifications de l’interface.

Les interfaces sont un moyen de définir des points d’extensibilité comme celui-ci. Le code qui communique avec une interface est plus faiblement couplé – en fait, il n’est couplé à aucun autre code spécifique. Il peut interagir avec des plugins écrits des années plus tard par des personnes n’ayant jamais rencontré le développeur d’origine.

You could instead use a base class with virtual functions – all plugins would be derived from the base class. But this is much more limiting because a class can only have one base class, whereas it can implement any number of interfaces.

C++ explanation.

Think of an interface as your classes public methods.

You then could create a template that ‘depends’ on these public methods in order to carry out it’s own function (it makes function calls defined in the classes public interface). Lets say this template is a container, like a Vector class, and the interface it depends on is a search algorithm.

Any algorithm class that defines the functions/interface Vector makes calls to will satisfy the ‘contract’ (as someone explained in the original reply). The algorithms don’t even need to be of the same base class; the only requirement is that the functions/methods that the Vector depends on (interface) is defined in your algorithm.

The point of all of this is that you could supply any different search algorithm/class just as long as it supplied the interface that Vector depends on (bubble search, sequential search, quick search).

You might also want to design other containers (lists, queues) that would harness the same search algorithm as Vector by having them fulfill the interface/contract that your search algorithms depends on.

This saves time (OOP principle ‘code reuse’) as you are able to write an algorithm once instead of again and again and again specific to every new object you create without over-complicating the issue with an overgrown inheritance tree.

As for ‘missing out’ on how things operate; big-time (at least in C++), as this is how most of the Standard TEMPLATE Library’s framework operates.

Of course when using inheritance and abstract classes the methodology of programming to an interface changes; but the principle is the same, your public functions/methods are your classes interface.

This is a huge topic and one of the the cornerstone principles of Design Patterns.

In Java these concrete classes all implement the CharSequence interface:

CharBuffer, Ssortingng, SsortingngBuffer, SsortingngBuilder

These concrete classes do not have a common parent class other than Object, so there is nothing that relates them, other than the fact they each have something to do with arrays of characters, representing such, or manipulating such. For instance, the characters of Ssortingng cannot be changed once a Ssortingng object is instantiated, whereas the characters of SsortingngBuffer or SsortingngBuilder can be edited.

Yet each one of these classes is capable of suitably implementing the CharSequence interface methods:

 char charAt(int index) int length() CharSequence subSequence(int start, int end) Ssortingng toSsortingng() 

In some cases Java class library classes that used to accept Ssortingng have been revised to now accept the CharSequence interface. So if you have an instance of SsortingngBuilder, instead of extracting a Ssortingng object (which means instantiating a new object instance), can instead just pass the SsortingngBuilder itself as it implements the CharSequence interface.

The Appendable interface that some classes implement has much the same kind of benefit for any situation where characters can be appended to an instance of the underlying concrete class object instance. All of these concrete classes implement the Appendable interface:

BufferedWriter, CharArrayWriter, CharBuffer, FileWriter, FilterWriter, LogStream, OutputStreamWriter, PipedWriter, PrintStream, PrintWriter, SsortingngBuffer, SsortingngBuilder, SsortingngWriter, Writer

In simple terms… If I’m writing a new class Swimmer to add the functionality swim() and need to use an object of class say Dog, and this Dog class implements interface Animal which declares swim()[To better understand…you may draw a diagram as to what I am talking about]. At the top of the hierarchy(Animal) it’s very abstract while at the bottom (Dog) it’s very concrete. The way I think about “programming to interfaces” is that, as I write Swimmer class, I want to write my code against the interface that’s as far up that hierarchy which in this case is Animal object. An interface is free from implementation details and thus makes your code loosely-coupled. The implementation details can be changed with time, however it would not affect the remaining code since all you are interacting is with the interface and not the implementation. You don’t care what the implementation is like…all you know is that there will be a class that would implement the interface.

short story:Postman is asked to go home by home and receive the covers contains (letters,documents,cheques,giftcard,application,loveletter) with address written on it to deliver.

Suppose there is no cover and ask post man to go home by home and receive all the things and deliver to other person the postman can get confuse,

so better wrap it with cover(in our story it is interface) then he will do his job fine.

Now postman job is to receive and deliver the covers only..(he dont bothered what is inside in the cover).

Create type of interface not actual type, but implement with actual type.

Create to interface means your components get Fits into the rest of code easily

I give you example.

you have AirPlane interface as below.

 interface Airplane{ parkPlane(); servicePlane(); } 

Suppose you have methods in your Controller class of Planes like

 parkPlane(Airplane plane) 

et

 servicePlane(Airplane plane) 

implemented in your program. It will not BREAK your code. I mean, it need not to change as long as it accepts arguments as AirPlane .

Because it will accept any Airplane despite of actual type, flyer , highflyr , fighter , etc.

Also, in a collection:

List plane; // Will take all your planes.

The following example will clear your understanding.


You have a fighter plane that implements it, so

 public class Fighter implements Airplane { public void parkPlane(){ // Specific implementations for fighter plane to park } public void servicePlane(){ // Specific implementatoins for fighter plane to service. } } 

The same thing for HighFlyer and other clasess:

 public class HighFlyer implements Airplane { public void parkPlane(){ // Specific implementations for HighFlyer plane to park } public void servicePlane(){ // specific implementatoins for HighFlyer plane to service. } } 

Now think your controller classes using AirPlane several times,

Suppose your Controller class is ControlPlane like below,

 public Class ControlPlane{ AirPlane plane; // so much method with AirPlane reference are used here... } 

here magic comes as

you may make your new AirPlane type instances as many as you want and you are not changing

code of ControlPlane class.

you can add instance..

 JumboJetPlane // implementing AirPlane interface. AirBus // implementing AirPlane interface. 

you may remove instances.. of previously created types too.

Q: – … “You could use any class that implements interface?”
A: – Yes.

Q: -… “When would you need to do that?”
A: – Each time you need a class(es) that implements interface(s).

Note: we couldn’t instantiate an interface not implemented by a classTrue.

  • Pourquoi?
  • because interface has only methods prototypes, not definitions (just functions names, not their logic)

AnIntf anInst = new Aclass();
// we could do this only if Aclass implements AnIntf.
// anInst will have Aclass reference.


Remarque:
Now we could understand what happend if Bclass and Cclass implements same Dintf.

 Dintf bInst = new Bclass(); // now we could call all Dintf functions implemented (defined) in Bclass. Dintf cInst = new Cclass(); // now we could call all Dintf functions implemented (defined) in Cclass. 

What we have:
same interface prototypes (functions names in interface), and call different implementations.

Bibliography:
Prototypes – wikipedia

Interface is like contract where you want your implementation class to implement methods written in contract(Interface).Since java does not provide multiple inheritance,programming to interface is a good way to achieve purpose of multiple inheritance.If you have a class A that is already extending some other class B but you want that class A should also follow certain guidelines or implement certain contract then you can do so by programming to interface strategy.

It can be advantageous to program to interfaces, even when we are not depending on abstractions.

Programming to interfaces forces us to use a contextually appropriate subset of an object. That helps because it:

  1. prevents us from doing contextually inappropriate things, and
  2. lets us safely change the implementation in the future.

For example, consider a Person class that implements the Friend and the Employee interface.

 class Person implements AbstractEmployee, AbstractFriend { } 

In the context of the person’s birthday, we program to the Friend interface, to prevent treating the person like an Employee .

 function party() { const friend: Friend = new Person("Kathryn"); friend.HaveFun(); } 

In the context of the person’s work, we program to the Employee interface, to prevent blurring workplace boundaries.

 function workplace() { const employee: Employee = new Person("Kathryn"); employee.DoWork(); } 

Génial. We have behaved appropriately in different contexts, and our software is working well.

Far into the future, if our business changes to work with dogs, we can change the software fairly easily. First, we create Dog class that implements both Friend and Employee . Then, we safely change new Person() to new Dog() . Even if both functions have thousands of lines of code, that simple edit will work because we know the following are true:

  1. Function party uses only the Friend subset of Person .
  2. Function workplace uses only the Employee subset of Person .
  3. Class Dog implements both the Friend and Employee interfaces.

On the other hand, if either party or workplace were to have programmed against Person , there would be a risk of both having Person -specific code. Changing from Person to Dog would require us to comb through the code to extirpate any Person -specific code that Dog does not support.

The moral : programming to interfaces helps our code to behave appropriately and to be ready for change. It also prepares our code to depend on abstractions, which brings even more advantages.

Also I see a lot of good and explanatory answers here, so I want to give my point of view here, including some extra information what I noticed when using this method.

Unit testing

For the last two years, I have written a hobby project and I did not write unit tests for it. After writing about 50K lines I found out it would be really necessary to write unit tests. I did not use interfaces (or very sparingly) … and when I made my first unit test, I found out it was complicated. Pourquoi?

Because I had to make a lot of class instances, used for input as class variables and/or parameters. So the tests look more like integration tests (having to make a complete ‘framework’ of classes since all was tied together).

Fear of interfaces So I decided to use interfaces. My fear was that I had to implement all functionality everywhere (in all used classes) multiple times. In some way this is true, however, by using inheritance it can be reduced a lot.

Combination of interfaces and inheritance I found out the combination is very good to be used. I give a very simple example.

 public interface IPricable { int Price { get; } } public interface ICar : IPricable public abstract class Article { public int Price { get { return ... } } } public class Car : Article, ICar { // Price does not need to be defined here } 

This way copying code is not necessary, while still having the benefit of using a car as interface (ICar).

Let’s start out with some definitions first:

Interface n. The set of all signatures defined by an object’s operations is called the interface to the object

Type n. A particular interface

A simple example of an interface as defined above would be all the PDO object methods such as query() , commit() , close() etc., as a whole, not separately. These methods, ie its interface define the complete set of messages, requests that can be sent to the object.

A type as defined above is a particular interface. I will use the made-up shape interface to demonstrate: draw() , getArea() , getPerimeter() etc..

If an object is of the Database type we mean that it accepts messages/requests of the database interface, query() , commit() etc.. Objects can be of many types. You can have a database object be of the shape type as long as it implements its interface, in which case this would be sub-typing .

Many objects can be of many different interfaces/types and implement that interface differently. This allows us to substitute objects, letting us choose which one to use. Also known as polymorphism.

The client will only be aware of the interface and not the implementation.

So in essence programming to an interface would involve making some type of abstract class such as Shape with the interface only specified ie draw() , getCoordinates() , getArea() etc.. And then have different concrete classes implement those interfaces such as a Circle class, Square class, Triangle class. Hence program to an interface not an implementation.

Program to an interface allows to change implementation of contract defined by interface seamlessly. It allows loose coupling between contract and specific implementations.

IInterface classRef = new ObjectWhatever()

You could use any class that implements IInterface? When would you need to do that?

Have a look at this SE question for good example.

Why should the interface for a Java class be preferred?

does using an Interface hit performance?

if so how much?

Oui. It will have slight performance overhead in sub-seconds. But if your application has requirement to change the implementation of interface dynamically, don’t worry about performance impact.

how can you avoid it without having to maintain two bits of code?

Don’t try to avoid multiple implementations of interface if your application need them. In absence of tight coupling of interface with one specific implementation, you may have to deploy the patch to change one implementation to other implementation.

One good use case: Implementation of Strategy pattern:

Real World Example of the Strategy Pattern

I don’t retain interface s are the most important thing in a language: it’s more commonly used the class inheriting. But anyway they are important!
For example (this is Java code, but it can simply adapted to C# or many other languages):

 interface Convertable { T convert(); } public class NumerableText implements Convertable { private Ssortingng text = ""; public NumerableText() { } public NumerableText(Ssortingng text) { this.text = text; } public Ssortingng getText() { return this.text; } public void setText(Ssortingng text) { this.text = text; } public Integer convert() { return this.text.hashCode(); } } public class NumerableTextArray implements Convertable { private Ssortingng[] textArray = ""; public NumerableTextArray() { } public NumerableTextArray(Ssortingng[] textArray) { this.textArray = textArray; } public Ssortingng[] getTextArray() { return this.textArray; } public void setTextArray(Ssortingng[] text) { this.textArray = textArray; } public Integer convert() { Integer value = 0; for (Ssortingng text : textArray) value += text.hashCode(); return value; } } public class Foo { public static void main() { Convertable num1 = new NumerableText("hello"); Convertable num2 = new NumerableTextArray(new Ssortingng[] { "test n°1", "test n°2" }); System.out.println(Ssortingng.valueOf(num1.convert())); System.out.println(Ssortingng.valueOf(num2.convert())); //Here are you two numbers generated from two classes of different type, but both with the method convert(), which allows you to get that number. } } 

Program to interface means dont provide hard codes right the way, means your codes should be extended without break the previous functionality….. just extensions not editing the prev codes