Coding alle interfacce?

Voglio consolidare la mia comprensione del concetto di “coding to interface”. A quanto ho capito, si creano interfacce per delineare le funzionalità previste e quindi si implementano questi “contratti” in classi concrete. Per usare l’ interfaccia si può semplicemente chiamare i metodi su un’istanza della class concreta.

L’ovvio vantaggio è conoscere la funzionalità fornita dalla class concreta, indipendentemente dalla sua specifica implementazione.

Sulla base di quanto sopra:

  1. Ci sono errori nella mia comprensione della “codifica per interfacce”?
  2. Ci sono dei vantaggi nella codifica delle interfacce che mi sono perso?

Grazie.

Una sola correzione ansible:

Per usare l’interfaccia si può semplicemente chiamare i metodi su un’istanza della class concreta.

Uno chiamerebbe i metodi su un riferimento dell’interfaccia di tipo, che capita di utilizzare la class concreta come implementazione:

List l = new ArrayList(); l.add("foo"); l.add("bar"); 

Se hai deciso di passare a un’altra implementazione List, il codice client funziona senza modifiche:

 List l = new LinkedList(); 

Questo è particolarmente utile per hide i dettagli di implementazione, generare automaticamente proxy, ecc.

Scoprirai che framework come spring e guice incoraggiano la programmazione su un’interfaccia. È la base per idee come la programmazione orientata agli aspetti, i proxy generati automaticamente per la gestione delle transazioni, ecc.

La tua comprensione sembra essere giusta. Il tuo collega di lavoro è appena passato dalla tua scrivania e ha tutte le ultime foto della festa di Natale con protagonista il tuo capo ubriaco caricato sul suo pollice. Il tuo collega e tu non ci pensi due volte su come funziona questa thumbdrive, ma è una scatola nera, ma sai che funziona grazie all’interfaccia USB .

Non importa se si tratta di un SanDisk o di un titanio (non è nemmeno sicuro che si tratti di un marchio), la dimensione / il colore non contano. In effetti, l’unica cosa che importa è che non è rotto (leggibile) e che si collega alla porta USB.

La tua thumbdrive USB si attiene a un contratto, è essenzialmente un’interfaccia. Si può supporre che adempia ad alcuni doveri fondamentali:

  1. Plug in USB
  2. Rispetta il metodo del contratto CopyDataTo:

    interfaccia pubblica IUSB {void CopyDataTo (string somePath); // utilizzato per copiare i dati dall’unità di anteprima a …}

  3. Rispetta il metodo del contratto CopyDataFrom:

    interfaccia pubblica IUSB {void CopyDataFrom (); // utilizzato per copiare i dati dal PC all’unità di anteprima}

Ok forse non quei metodi, ma l’interfaccia IUSB è solo un contratto che i produttori di unità di thumbnail devono rispettare per garantire la funzionalità su varie piattaforms / fornitori. Quindi SanDisk fa il loro pollice in mano dall’interfaccia:

 public class SanDiskUSB : IUSB { //todo: define methods of the interface here } 

Ari, penso che tu abbia già una solida comprensione (da come sembra) su come funzionano le interfacce.

Il vantaggio principale è che l’uso di un’interfaccia accoppia liberamente una class con le sue dipendenze. È quindi ansible modificare una class o implementare una nuova implementazione di interfaccia concreta senza dover modificare le classi che dipendono da essa.

Per usare l’interfaccia si può semplicemente chiamare i metodi su un’istanza della class concreta.

In genere si avrebbe una variabile tipizzata sul tipo di interfaccia, consentendo in tal modo solo l’accesso ai metodi definiti nell’interfaccia.

L’ovvio vantaggio è conoscere la funzionalità fornita dalla class concreta, indipendentemente dalla sua specifica implementazione.

Una specie di. La cosa più importante, ti permette di scrivere API che prendono parametri con tipi di interfaccia. Gli utenti dell’API possono quindi passare nelle proprie classi (che implementano tali interfacce) e il codice funzionerà su quelle classi anche se non esistevano ancora quando è stato scritto (come ad esempio java.util.Arrays.sort () in grado di ordinare tutto ciò che implementa Comparable o fornito con un Comparator adatto).

Dal punto di vista del design, le interfacce consentono / impongono una chiara separazione tra i contratti API e i dettagli di implementazione.

Lo scopo di codificare le interfacce è quello di separare il codice dall’implementazione concreta in uso. Cioè, il tuo codice non farà ipotesi sul tipo concreto, solo sull’interfaccia. Di conseguenza, l’implementazione concreta può essere scambiata senza dover modificare il codice.

Non hai elencato la parte su come ottieni un’implementazione dell’interfaccia, che è importante. Se istanziate esplicitamente la class di implementazione con un costruttore, il vostro codice è legato a tale implementazione. Puoi usare una fabbrica per ottenere un’istanza per te, ma poi sei legato alla fabbrica come prima nella class di implementazione. La terza alternativa consiste nell’utilizzare dependency injection, che sta avendo una factory plug l’object di implementazione nell’object che la usa, nel qual caso si evita di avere la class che utilizza l’object che è legato alla class di implementazione o a una factory.

Penso che tu possa aver accennato a questo, ma credo che uno dei maggiori vantaggi della codifica su un’interfaccia sia la tua dipendenza da un’implementazione concreta. È ansible ottenere un accoppiamento lento e semplificare la commutazione di implementazioni specifiche senza modificare molto codice. Se stai semplicemente imparando, darei un’occhiata ai vari modelli di progettazione e al modo in cui risolvono i problemi codificando per interfacce. Leggendo il libro Head First: Design Patterns ha davvero aiutato le cose a fare clic su di me.

A quanto ho capito, si creano interfacce per delineare le funzionalità previste e quindi si implementano questi “contratti” in classi concrete.

L’unico tipo di mutazione che vedo nel tuo modo di pensare è questo: stai per chiamare i contratti previsti, funzionalità non prevista. La funzionalità è implementata nelle classi concrete. L’interfaccia afferma solo che sarà ansible chiamare qualcosa che implementa l’interfaccia con le firme dei metodi previste. La funzionalità è nascosta dall’object chiamante.

Ciò ti consentirà di estendere il tuo pensiero al polimorfismo come segue.

 SoundMaker sm = new Duck();
SoundMaker sm1 = new ThunderousCloud(); sm.makeSound(); // quack, calls all sorts of stuff like larynx, etc.
sm1.makeSound(); // BOOM!, completely different operations here...