Che cosa significa “programmare su un’interfaccia”?

Ho visto questo accennato alcune volte e non sono chiaro su cosa significhi. Quando e perché vorresti farlo?

So quali interfacce fare, ma il fatto che non sono chiaro su questo mi fa pensare che mi sto perdendo per usarle correttamente.

È così se dovessi fare:

IInterface classRef = new ObjectWhatever() 

Potresti usare qualsiasi class che implementa IInterface ? Quando avresti bisogno di farlo? L’unica cosa che riesco a pensare è se hai un metodo e non sei sicuro di quale object sarà superato aspettandoti di implementare IInterface . Non riesco a pensare a quanto spesso avresti bisogno di farlo … (Inoltre, come potresti scrivere un metodo che include un object che implementa un’interfaccia? È ansible?)

Scusa se ho completamente perso il punto.

Ci sono alcune risposte meravigliose qui a queste domande che entrano in tutti i tipi di dettagli sulle interfacce e accoppiano liberamente codice, inversione di controllo e così via. Ci sono alcune discussioni piuttosto inebrianti, quindi mi piacerebbe cogliere l’occasione per rompere le cose un po ‘per capire perché un’interfaccia è utile.

Quando ho iniziato a essere esposto alle interfacce, anch’io ero confuso riguardo alla loro rilevanza. Non ho capito perché ne avessi bisogno. Se stiamo usando un linguaggio come Java o C #, abbiamo già ereditarietà e ho visto le interfacce come una forma più debole di ereditarietà e pensiero, “perché preoccuparsi?” In un certo senso avevo ragione, puoi pensare alle interfacce come a una debole forma di ereditarietà, ma oltre a questo ho finalmente capito il loro uso come un costrutto linguistico pensando a loro come un mezzo per classificare tratti o comportamenti comuni che sono stati esibiti da potenzialmente molte classi di oggetti non correlate.

Ad esempio, diciamo che hai un gioco di carte SIM e hai le seguenti classi:

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

Chiaramente, questi due oggetti non hanno nulla in comune in termini di ereditarietà diretta. Ma, si potrebbe dire che sono entrambi fastidiosi.

Diciamo che il nostro gioco deve avere una sorta di cosa casuale che infastidisce il giocatore quando mangia la cena. Questo potrebbe essere un HouseFly o un Telemarketer o entrambi – ma come consentire entrambi con una singola funzione? E come si chiede a ogni diverso tipo di object di “fare la loro cosa fastidiosa” allo stesso modo?

La chiave per capire è che sia un Telemarketer che HouseFly condividono un comportamento comune interpretato in modo HouseFly , anche se non sono uguali in termini di modellazione. Quindi, creiamo un’interfaccia che entrambi possano implementare:

  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(); } } 

Ora abbiamo due classi che possono essere fastidiose a modo loro. E non hanno bisogno di derivare dalla stessa class base e condividere caratteristiche intrinseche comuni – hanno semplicemente bisogno di soddisfare il contratto di IPest – quel contratto è semplice. Devi solo essere BeAnnoying . A questo proposito, possiamo modellare il seguente:

  class DiningRoom { DiningRoom(Person[] diningPeople, IPest[] pests) { ... } void ServeDinner() { when diningPeople are eating, foreach pest in pests pest.BeAnnoying(); } } 

Qui abbiamo una sala da pranzo che accetta un numero di commensali e un numero di parassiti – nota l’uso dell’interfaccia. Ciò significa che nel nostro piccolo mondo, un membro dell’array di pests potrebbe effettivamente essere un object Telemarketer o un object HouseFly .

Il metodo ServeDinner viene chiamato quando viene servita la cena e la nostra gente nella sala da pranzo dovrebbe mangiare. Nel nostro piccolo gioco, è così che i nostri parassiti fanno il loro lavoro – ogni pest viene istruito a essere fastidioso attraverso l’interfaccia IPest . In questo modo, possiamo facilmente avere sia Telemarketers che HouseFlys fastidiosi in ciascuno dei loro modi: ci interessa solo che abbiamo qualcosa nell’object DiningRoom che è una peste, non ci interessa davvero cosa sia e potrebbero non avere nulla in comune con gli altri.

Questo esempio di pseudo-codice molto elaborato (che è stato trascinato molto più a lungo di quanto mi aspettassi) ha semplicemente lo scopo di illustrare il tipo di cosa che alla fine ha acceso la luce in termini di quando potremmo usare un’interfaccia. Mi scuso in anticipo per la stupidità dell’esempio, ma spero che ciò aiuti nella comprensione. E, per essere sicuro, le altre risposte pubblicate che hai ricevuto qui coprono davvero la gamma di utilizzo delle interfacce oggi nei modelli di progettazione e nelle metodologie di sviluppo.

L’esempio specifico che ho usato per dare agli studenti è che dovrebbero scrivere

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

invece di

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

Questi sembrano esattamente gli stessi in un programma breve, ma se vai avanti con myList 100 volte nel tuo programma puoi iniziare a vedere una differenza. La prima dichiarazione garantisce di chiamare solo metodi su myList definiti dall’interfaccia List (quindi nessun metodo specifico di ArrayList ). Se hai programmato l’interfaccia in questo modo, in seguito puoi decidere che ne hai davvero bisogno

 List myList = new TreeList(); 

e devi solo cambiare il tuo codice in quel punto. Sai già che il resto del tuo codice non fa nulla che potrebbe essere rotto cambiando l’ implementazione perché hai programmato l’ interfaccia .

I vantaggi sono ancora più evidenti (penso) quando parli di parametri del metodo e valori di ritorno. Prendi questo ad esempio:

 public ArrayList doSomething(HashMap map); 

Questa dichiarazione di metodo ti lega a due implementazioni concrete ( ArrayList e HashMap ). Non appena quel metodo viene chiamato da un altro codice, qualsiasi modifica a quei tipi probabilmente significa che dovrai cambiare anche il codice chiamante. Sarebbe meglio programmare le interfacce.

 public List doSomething(Map map); 

Ora non importa che tipo di List restituisci o quale tipo di Map viene passato come parametro. Le modifiche apportate al metodo doSomething non doSomething di modificare il codice chiamante.

La programmazione di un’interfaccia sta dicendo: “Ho bisogno di questa funzionalità e non mi interessa da dove provenga”.

Considerare (in Java), l’interfaccia List rispetto alle classi concrete ArrayList e LinkedList . Se tutto quello che mi interessa è che ho una struttura dati contenente più elementi di dati a cui dovrei accedere tramite iterazione, sceglierei una List (e questo è il 99% delle volte). Se so che ho bisogno di inserire / eliminare a tempo costante da entrambe le estremità della lista, potrei scegliere l’implementazione concreta di LinkedList (o più probabilmente, usare l’interfaccia della coda ). Se so che ho bisogno dell’accesso casuale per indice, sceglierei la class concreta ArrayList .

L’utilizzo delle interfacce è un fattore chiave per rendere il tuo codice facilmente testabile oltre a rimuovere gli accoppiamenti non necessari tra le tue classi. Creando un’interfaccia che definisce le operazioni sulla class, consenti alle classi che desiderano utilizzare quella funzionalità di utilizzarla senza dipendere direttamente dalla class di implementazione. Se in seguito si decide di cambiare e utilizzare un’implementazione diversa, è necessario modificare solo la parte del codice in cui viene implementata l’implementazione. Il resto del codice non deve cambiare perché dipende dall’interfaccia, non dalla class di implementazione.

Questo è molto utile nella creazione di test unitari. Nella class sotto test lo si deve dipendere dall’interfaccia e iniettare un’istanza dell’interfaccia nella class (o una factory che consente di creare istanze dell’interfaccia, se necessario) tramite il costruttore o un settor di proprietà. La class utilizza l’interfaccia fornita (o creata) nei suoi metodi. Quando si va a scrivere i test, è ansible simulare o falsificare l’interfaccia e fornire un’interfaccia che risponda ai dati configurati nel test dell’unità. Puoi farlo perché la tua class sottoposta a test tratta solo l’interfaccia, non la tua implementazione concreta. Qualunque class che implementa l’interfaccia, compresa la tua class finta o falsa, lo farà.

EDIT: Di seguito è riportato un collegamento a un articolo in cui Erich Gamma discute la sua citazione, “Programma su un’interfaccia, non su un’implementazione.”

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

Dovresti esaminare Inversion of Control:

  • Martin Fowler: inversione dei contenitori di controllo e il modello di iniezione delle dipendenze
  • Wikipedia: Inversion of Control

In uno scenario del genere, non dovresti scrivere questo:

 IInterface classRef = new ObjectWhatever(); 

Scriveresti qualcosa del genere:

 IInterface classRef = container.Resolve(); 

Questo andrebbe in una configurazione basata su regole nell’object container e costruirà per te l’object reale, che potrebbe essere ObjectWhatever. L’importante è che tu possa sostituire questa regola con qualcosa che utilizza un altro tipo di object e il tuo codice funzionerà comunque.

Se lasciamo IoC fuori dal tavolo, puoi scrivere codice che sa che può parlare con un object che fa qualcosa di specifico , ma non quale tipo di object o come lo fa.

Questo sarebbe utile quando si passano i parametri.

Per quanto riguarda la tua domanda tra parentesi “Inoltre, come potresti scrivere un metodo che accetta un object che implementa un’interfaccia? È ansible?”, In C # devi semplicemente utilizzare il tipo di interfaccia per il tipo di parametro, in questo modo:

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

Questo si inserisce direttamente nel “parlare con un object che fa qualcosa di specifico”. Il metodo sopra definito sa cosa aspettarsi dall’object, implementa tutto in IInterface, ma non gli importa quale tipo di object sia, solo che aderisce al contratto, che è ciò che è un’interfaccia.

Ad esempio, probabilmente hai familiarità con i calcolatori e probabilmente ne hai usati parecchi durante le tue giornate, ma la maggior parte delle volte sono tutti diversi. Tu, d’altra parte, sai come dovrebbe funzionare una calcolatrice standard, quindi sei in grado di usarli tutti, anche se non puoi usare le caratteristiche specifiche di ciascuna calcolatrice che nessuna delle altre ha.

Questa è la bellezza delle interfacce. Puoi scrivere una parte di codice, che sa che otterrà degli oggetti che possono aspettarsi determinati comportamenti. A nessuno importa quale tipo di object sia, solo che supporta il comportamento necessario.

Permettetemi di darvi un esempio concreto.

Abbiamo un sistema di traduzione personalizzato per i moduli di Windows. Questo sistema scorre i controlli su un modulo e traduce il testo in ciascuno. Il sistema sa come gestire i controlli di base, come la proprietà-type-of-control-that-has-a-Text, e cose di base simili, ma per qualcosa di base, non è sufficiente.

Ora, dal momento che i controlli ereditano da classi predefinite su cui non abbiamo alcun controllo, potremmo fare una delle tre cose:

  1. Costruisci il supporto per il nostro sistema di traduzione per rilevare in particolare il tipo di controllo con cui lavora e traduci i bit corretti (incubo di manutenzione)
  2. Costruisci il supporto in classi di base (imansible, dal momento che tutti i controlli ereditano da diverse classi predefinite)
  3. Aggiungi il supporto dell’interfaccia

Quindi abbiamo fatto nr. 3. Tutti i nostri controlli implementano ILocalizable, che è un’interfaccia che ci dà un metodo, la capacità di tradurre “stesso” in un contenitore di testo / regole di traduzione. In quanto tale, il modulo non ha bisogno di sapere quale tipo di controllo ha trovato, solo che implementa l’interfaccia specifica e sa che esiste un metodo in cui può chiamare per localizzare il controllo.

La programmazione su un’interfaccia non ha assolutamente nulla a che fare con le interfacce astratte come vediamo in Java o in .NET. Non è nemmeno un concetto di OOP.

Ciò che significa in realtà è non andare in giro con le parti interne di un object o di una struttura di dati. Usa l’interfaccia del programma astratto, o API, per interagire con i tuoi dati. In Java o C # significa che si utilizzano proprietà e metodi pubblici invece dell’accesso al campo non elaborato. Per C ciò significa utilizzare le funzioni anziché i puntatori grezzi.

EDIT: E con i database significa utilizzare le viste e le stored procedure invece dell’accesso diretto alla tabella.

Codice all’interfaccia Non l’implementazione NON ha NIENTE da fare con Java, né il suo costrutto di interfaccia.

Questo concetto è stato portato alla ribalta nei libri di Patterns / Gang of Four, ma probabilmente lo è stato anche molto prima. Il concetto esisteva sicuramente molto prima che Java esistesse.

Il costrutto Java Interface è stato creato per aiutare questa idea (tra le altre cose), e le persone sono diventate troppo concentrate sul costrutto come il centro del significato piuttosto che l’intento originale. Tuttavia, è la ragione per cui abbiamo metodi e attributi pubblici e privati ​​in Java, C ++, C #, ecc.

Significa solo interagire con l’interfaccia pubblica di un object o di un sistema. Non preoccuparti o addirittura prevedere come funziona internamente. Non preoccuparti di come è implementato. Nel codice orientato agli oggetti, è il motivo per cui abbiamo metodi / attributi pubblici o privati. Si intende utilizzare i metodi pubblici perché i metodi privati ​​sono disponibili solo internamente, all’interno della class. Costituiscono l’implementazione della class e possono essere modificati come richiesto senza modificare l’interfaccia pubblica. Supponiamo che per quanto riguarda la funzionalità, un metodo su una class eseguirà la stessa operazione con lo stesso risultato previsto ogni volta che lo chiami con gli stessi parametri. Permette all’autore di cambiare il modo in cui la class funziona, la sua implementazione, senza rompere il modo in cui le persone interagiscono con esso.

E puoi programmare l’interfaccia, non l’implementazione senza mai usare un costrutto di interfaccia. È ansible programmare sull’interfaccia non l’implementazione in C ++, che non ha un costrutto di interfaccia. È ansible integrare due sistemi aziendali di grandi dimensioni in modo molto più robusto, purché interagiscano tramite interfacce pubbliche (contratti) anziché chiamare metodi su oggetti interni ai sistemi. Ci si aspetta che le interfacce reagiscano sempre allo stesso modo previsto in base agli stessi parametri di input; se implementato per l’interfaccia e non l’implementazione. Il concetto funziona in molti posti.

Scuotere l’idea che le interfacce Java abbiano qualcosa che mai ha a che fare con il concetto di “Programma per l’interfaccia, non per l’implementazione”. Possono aiutare ad applicare il concetto, ma non sono il concetto.

Sembra che tu capisca come funzionano le interfacce ma non sei sicuro di quando usarle e quali vantaggi offrono. Ecco alcuni esempi di quando un’interfaccia avrebbe senso:

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

quindi potrei creare GoogleSearchProvider, YahooSearchProvider, LiveSearchProvider ecc.

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

quindi creare JpegImageLoader, GifImageLoader, PngImageLoader, ecc.

La maggior parte dei componenti aggiuntivi e dei sistemi plug-in risolvono le interfacce.

Un altro uso popolare è per il modello di repository. Dire che voglio caricare un elenco di codici postali da diverse fonti

 interface IZipCodeRepository { IList GetZipCodes(string state); } 

quindi potrei creare un XMLZipCodeRepository, SQLZipCodeRepository, CSVZipCodeRepository, ecc. Per le mie applicazioni web, creo spesso repository XML in anticipo, così posso ottenere qualcosa in esecuzione prima che il database Sql sia pronto. Una volta che il database è pronto, scrivo un SQLRepository per sostituire la versione XML. Il resto del mio codice rimane invariato dal momento che funziona solo su interfacce.

I metodi possono accettare interfacce come:

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

Rende il tuo codice molto più estensibile e più facile da mantenere quando hai serie di classi simili. Sono un programmatore junior, quindi non sono un esperto, ma ho appena finito un progetto che richiedeva qualcosa di simile.

Lavoro su software client che parla con un server che esegue un dispositivo medico. Stiamo sviluppando una nuova versione di questo dispositivo che ha alcuni nuovi componenti che il cliente deve configurare a volte. Esistono due tipi di nuovi componenti e sono diversi, ma sono anche molto simili. Fondamentalmente, ho dovuto creare due moduli di configurazione, due liste di classi, due di tutto.

Ho deciso che sarebbe meglio creare una class di base astratta per ciascun tipo di controllo che potesse contenere quasi tutta la logica reale e quindi i tipi derivati ​​per occuparsi delle differenze tra i due componenti. Tuttavia, le classi base non sarebbero state in grado di eseguire operazioni su questi componenti se dovessi preoccuparmi dei tipi tutto il tempo (beh, avrebbero potuto, ma ci sarebbe stata un’istruzione “if” o un passaggio in ogni metodo) .

Ho definito un’interfaccia semplice per questi componenti e tutte le classi base parlano con questa interfaccia. Ora, quando cambio qualcosa, praticamente “funziona” dappertutto e non ho la duplicazione del codice.

Se si programma in Java, JDBC è un buon esempio. JDBC definisce un insieme di interfacce ma non dice nulla sull’implementazione. Le tue applicazioni possono essere scritte contro questo insieme di interfacce. In teoria, scegli alcuni driver JDBC e la tua applicazione funzionerà. Se scopri che c’è un driver JDBC più veloce o “migliore” o più economico o per qualsiasi ragione, puoi in teoria riconfigurare il tuo file di proprietà e, senza dover apportare alcuna modifica alla tua applicazione, la tua applicazione funzionerebbe ancora.

La programmazione sulle interfacce è eccezionale, promuove l’accoppiamento lento. Come @lassevk menzionato, Inversion of Control è un grande uso di questo.

Inoltre, esaminare i principal SOLID . ecco una serie di video

Passa attraverso un esempio codificato (fortemente accoppiato), quindi guarda le interfacce, infine passa a uno strumento IoC / DI (NInject)

Oltre alla risposta già selezionata (e ai vari post informativi qui), ti consiglio vivamente di prendere una copia di Head First Design Patterns . È una lettura molto semplice e risponderà direttamente alla tua domanda, spiegherà perché è importante e ti mostrerà molti schemi di programmazione che puoi utilizzare per utilizzare tale principio (e altri).

Un sacco di spiegazioni là fuori, ma per renderlo ancora più semplice. Prendi ad esempio una List . Si può implementare un elenco con:

  1. una matrice interna
  2. Una lista collegata
  3. altra implementazione

Creando un’interfaccia, dì una List . Si codifica solo per la definizione di List o cosa significa List in realtà.

È ansible utilizzare qualsiasi tipo di implementazione internamente per dire un’implementazione array . Ma supponiamo che tu voglia cambiare l’implementazione per qualche ragione dire un bug o una performance. Quindi è sufficiente modificare la dichiarazione List ls = new ArrayList() in List ls = new LinkedList() .

No dove altro nel codice, dovrai cambiare qualcos’altro? Perché tutto il resto è stato costruito sulla definizione di List .

Sono in ritardo con questa domanda, ma voglio menzionare qui che la linea “Programma per un’interfaccia, non un’implementazione” ha avuto una buona discussione nel libro dei modelli di design GoF (Gang of Four).

Ha dichiarato, a p. 18:

Programma su un’interfaccia, non un’implementazione

Non dichiarare le variabili come istanze di particolari classi concrete. Invece, commetti solo su un’interfaccia definita da una class astratta. Troverete che questo è un tema comune degli schemi di progettazione in questo libro.

e soprattutto, è iniziato con:

Ci sono due vantaggi nella manipolazione degli oggetti solo in termini dell’interfaccia definita dalle classi astratte:

  1. I client rimangono inconsapevoli dei tipi specifici di oggetti che usano, a patto che gli oggetti aderiscano all’interfaccia che i clienti si aspettano.
  2. I client rimangono inconsapevoli delle classi che implementano questi oggetti. I client conoscono solo le classi astratte che definiscono l’interfaccia.

Quindi, in altre parole, non scrivere le tue classi in modo che abbia un metodo quack() per anatre e quindi un metodo bark() per i cani, perché sono troppo specifici per una particolare implementazione di una class (o sottoclass) . Invece, scrivi il metodo usando nomi che sono abbastanza generali da essere usati nella class base, come giveSound() o move() , in modo che possano essere usati per anatre, cani o persino auto, e poi il client del tuo le classi possono semplicemente dire .giveSound() piuttosto che pensare a usare quack() o bark() o persino a determinare il tipo prima di inviare il messaggio corretto da inviare all’object.

Per aggiungere ai post esistenti, a volte la codifica delle interfacce aiuta nei progetti di grandi dimensioni quando gli sviluppatori lavorano simultaneamente su componenti separati. Tutto ciò che serve è definire le interfacce in anticipo e scrivere loro il codice mentre altri sviluppatori scrivono il codice nell’interfaccia che si sta implementando.

È anche un bene per il test unitario, puoi inserire le tue classi (che soddisfano i requisiti dell’interfaccia) in una class che dipende da esso

Quindi, giusto per farlo, il vantaggio di un’interfaccia è che posso separare la chiamata di un metodo da una particolare class. Invece di creare un’istanza dell’interfaccia, in cui l’implementazione viene fornita da qualsiasi class che scelgo che implementa quell’interfaccia. Mi consente quindi di avere molte classi, che hanno funzionalità simili ma leggermente diverse e in alcuni casi (i casi relativi all’intenzione dell’interfaccia) non si preoccupano di quale object sia.

Ad esempio, potrei avere un’interfaccia di movimento. Un metodo che rende qualcosa ‘mossa’ e qualsiasi object (Persona, Automobile, Gatto) che implementa l’interfaccia di movimento potrebbe essere passato e detto di muoversi. Senza il metodo, tutti conoscono il tipo di class che è.

Immagina di avere un prodotto chiamato “Zebra” che può essere esteso dai plugin. Trova i plugin cercando le DLL in qualche directory. Carica tutte quelle DLL e utilizza la reflection per trovare le classi che implementano IZebraPlugin , quindi chiama i metodi di tale interfaccia per comunicare con i plugin.

This makes it completely independent of any specific plugin class – it doesn’t care what the classs are. It only cares that they fulfill the interface specification.

Interfaces are a way of defining points of extensibility like this. Code that talks to an interface is more loosely coupled – in fact it is not coupled at all to any other specific code. It can inter-operate with plugins written years later by people who have never met the original developer.

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 classs 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 classs 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 classs the methodology of programming to an interface changes; but the principle is the same, your public functions/methods are your classs interface.

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

In Java these concrete classs all implement the CharSequence interface:

CharBuffer, String, StringBuffer, StringBuilder

These concrete classs 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 String cannot be changed once a String object is instantiated, whereas the characters of StringBuffer or StringBuilder can be edited.

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

 char charAt(int index) int length() CharSequence subSequence(int start, int end) String toString() 

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

The Appendable interface that some classs 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 classs implement the Appendable interface:

BufferedWriter, CharArrayWriter, CharBuffer, FileWriter, FilterWriter, LogStream, OutputStreamWriter, PipedWriter, PrintStream, PrintWriter, StringBuffer, StringBuilder, StringWriter, 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) 

e

 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 classs 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.

  • why?
  • 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.


Nota:
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(); } 

Grande. 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. Perché?

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 classs 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 classs) 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 classs 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?

Sì. 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 String text = ""; public NumerableText() { } public NumerableText(String text) { this.text = text; } public String getText() { return this.text; } public void setText(String text) { this.text = text; } public Integer convert() { return this.text.hashCode(); } } public class NumerableTextArray implements Convertable { private String[] textArray = ""; public NumerableTextArray() { } public NumerableTextArray(String[] textArray) { this.textArray = textArray; } public String[] getTextArray() { return this.textArray; } public void setTextArray(String[] text) { this.textArray = textArray; } public Integer convert() { Integer value = 0; for (String text : textArray) value += text.hashCode(); return value; } } public class Foo { public static void main() { Convertable num1 = new NumerableText("hello"); Convertable num2 = new NumerableTextArray(new String[] { "test n°1", "test n°2" }); System.out.println(String.valueOf(num1.convert())); System.out.println(String.valueOf(num2.convert())); //Here are you two numbers generated from two classs 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