Un’interfaccia software può riferirsi a una vasta gamma di diversi tipi di interfaccia a diversi “livelli”: un sistema operativo può interfacciarsi con pezzi di hardware. Le applicazioni o i programmi in esecuzione sul sistema operativo potrebbero dover interagire tramite flussi di dati, filtri e pipeline; e nei programmi orientati agli oggetti, gli oggetti all’interno di un’applicazione potrebbero dover interagire tramite metodi.
In praticamodifica
Un principio chiave del design è quello di vietare l’accesso a tutte le risorse per impostazione predefinita, consentendo l’accesso solo attraverso punti di ingresso ben definiti, cioè interfacce. Le interfacce software forniscono l’accesso alle risorse del computer (come memoria, CPU, storage, ecc.) del sistema informatico sottostante; l’accesso diretto (cioè, non attraverso interfacce ben progettate) a tali risorse da parte del software può avere importanti ramificazioni-a volte disastrose—per funzionalità e stabilità.
Le interfacce tra i componenti software possono fornire costanti, tipi di dati, tipi di procedure, specifiche di eccezione e firme di metodo. A volte, le variabili pubbliche sono anche definite come parte di un’interfaccia.
L’interfaccia di un modulo software A è deliberatamente definita separatamente dall’implementazione di quel modulo. Quest’ultimo contiene il codice effettivo delle procedure e dei metodi descritti nell’interfaccia, nonché altre variabili “private”, procedure, ecc. Un altro modulo software B, ad esempio il client ad A, che interagisce con A è costretto a farlo solo attraverso l’interfaccia pubblicata. Un vantaggio pratico di questa disposizione è che la sostituzione dell’implementazione di A con un’altra implementazione della stessa interfaccia non dovrebbe causare il fallimento di B—il modo in cui A soddisfa internamente i requisiti dell’interfaccia non è rilevante per B, che riguarda solo le specifiche dell’interfaccia. (Vedi anche principio di sostituzione di Liskov.)
In linguaggi orientati agli oggettimodifica
In alcuni linguaggi orientati agli oggetti, specialmente quelli senza ereditarietà multipla completa, il termine interfaccia viene utilizzato per definire un tipo astratto che non contiene dati ma definisce i comportamenti come firme di metodo. Una classe con codice e dati per tutti i metodi corrispondenti a quell’interfaccia e dichiarando così si dice di implementare quell’interfaccia. Inoltre, anche nei linguaggi a ereditarietà singola, si possono implementare più interfacce, e quindi possono essere di tipi diversi allo stesso tempo.
Un’interfaccia è quindi una definizione di tipo; ovunque un oggetto possa essere scambiato (ad esempio, in una funzione o in una chiamata di metodo) il tipo dell’oggetto da scambiare può essere definito in termini di una delle sue interfacce implementate o classi di base piuttosto che specificare la classe specifica. Questo approccio significa che qualsiasi classe che implementa tale interfaccia può essere utilizzata. Ad esempio, un’implementazione fittizia può essere utilizzata per consentire allo sviluppo di progredire prima che l’implementazione finale sia disponibile. In un altro caso, un’implementazione falsa o finta può essere sostituita durante il test. Tali implementazioni di stub sono sostituite da codice reale più avanti nel processo di sviluppo.
Di solito un metodo definito in un’interfaccia non contiene codice e quindi non può essere chiamato; deve essere implementato da un codice non astratto per essere eseguito quando viene invocato. Un’interfaccia chiamata ” Stack
” potrebbe definire due metodi: push()
e pop()
. Può essere implementato in diversi modi, ad esempioFastStack
eGenericStack
—il primo è veloce, lavora con una struttura dati di dimensioni fisse e il secondo utilizza una struttura dati che può essere ridimensionata, ma a costo di una velocità leggermente inferiore.
Sebbene le interfacce possano contenere molti metodi, possono contenere solo uno o addirittura nessuno. Ad esempio, il linguaggio Java definisce l’interfaccia Readable
che ha il singolo read()
metodo; varie implementazioni sono utilizzate per scopi diversi, tra cui BufferedReader
FileReader
InputStreamReader
PipedReader
eStringReader
. Le interfacce marker come Serializable
non contengono alcun metodo e servono a fornire informazioni di runtime all’elaborazione generica utilizzando Reflection.
Programmazione all’interfacciaedit
L’uso delle interfacce consente uno stile di programmazione chiamato programmazione all’interfaccia. L’idea alla base di questo approccio è di basare la logica di programmazione sulle interfacce degli oggetti utilizzati, piuttosto che sui dettagli interni dell’implementazione. La programmazione all’interfaccia riduce la dipendenza dalle specifiche di implementazione e rende il codice più riutilizzabile.
Spingendo questa idea all’estremo, inversion of control lascia il contesto per iniettare il codice con le implementazioni specifiche dell’interfaccia che verrà utilizzata per eseguire il lavoro.