Perché le interfacce sono utili?


158

Ho studiato e codificato in C # da un po 'di tempo ormai. Tuttavia, non riesco a capire l'utilità delle interfacce. Portano troppo poco al tavolo. Oltre a fornire le firme della funzione, non fanno nulla. Se riesco a ricordare i nomi e la firma delle funzioni che devono essere implementate, non ce n'è bisogno. Sono lì solo per assicurarsi che le suddette funzioni (nell'interfaccia) siano implementate nella classe ereditaria.

C # è un linguaggio eccezionale, ma a volte ti dà la sensazione che prima Microsoft crei il problema (non consentendo l'ereditarietà multipla) e quindi fornisca la soluzione, che è piuttosto noiosa.

Questa è la mia comprensione che si basa su un'esperienza di codifica limitata. Cosa ne pensi delle interfacce? Quanto spesso li usi e cosa ti fa fare?


55
"Se riesco a ricordare i nomi e la firma delle funzioni che devono essere implementate, non è necessario per loro." Questa affermazione mi fa sospettare che dovresti esaminare un po 'di più i vantaggi delle lingue tipizzate staticamente .
Steven Jeuris,

37
Dimentica C #, dimentica Java, dimentica la lingua. Sta semplicemente pensando in termini di OO. Ti incoraggio a raccogliere del materiale di lettura da gente come Robert C. Martin, Martin Fowler, Michael Feathers, la banda dei quattro, ecc., In quanto ti aiuterà a espandere il tuo pensiero.
Anthony Pegram,

27
Mi ci sono voluti più di due anni per capire davvero a cosa servivano le interfacce. Il mio consiglio: studia i modelli di design. Poiché la maggior parte di essi si basa su interfacce, capirai rapidamente perché sono così utili.
Oliver Weiler,

37
Hai molto da imparare amico.
ChaosPandion,

60
@ChaosPandion abbiamo tutti molto da imparare
kenwarner

Risposte:


151

Sono lì solo per assicurarsi che le suddette funzioni (nell'interfaccia) siano implementate nella classe ereditaria.

Corretta. Questo è un vantaggio sufficientemente impressionante per giustificare la funzionalità. Come altri hanno già detto, un'interfaccia è un obbligo contrattuale di implementare determinati metodi, proprietà ed eventi. Il vantaggio convincente di un linguaggio tipicamente statico è che il compilatore può verificare che un contratto su cui si basa il codice sia effettivamente rispettato.

Detto questo, le interfacce sono un modo abbastanza debole di rappresentare gli obblighi contrattuali. Se si desidera un modo più forte e flessibile per rappresentare gli obblighi contrattuali, esaminare la funzionalità Contratti di codice fornita con l'ultima versione di Visual Studio.

C # è un linguaggio eccezionale, ma a volte ti dà la sensazione che prima Microsoft crei il problema (non consentendo l'ereditarietà multipla) e quindi fornisca la soluzione, che è piuttosto noiosa.

Beh, sono contento che ti piaccia.

Tutti i progetti software complessi sono il risultato della valutazione reciproca di funzioni contrastanti e del tentativo di trovare il "punto ottimale" che offre grandi vantaggi a costi contenuti. Abbiamo imparato attraverso un'esperienza dolorosa che le lingue che consentono l'ereditarietà multipla ai fini della condivisione dell'implementazione presentano vantaggi relativamente piccoli e costi relativamente elevati. Consentire l'ereditarietà multipla solo sulle interfacce, che non condividono i dettagli dell'implementazione, offre molti dei vantaggi dell'ereditarietà multipla senza la maggior parte dei costi.


Stavo solo leggendo "Microsoft crea il problema non consentendo l'ereditarietà multipla" e ho pensato che Eric Lippert avrebbe avuto qualcosa da dire al riguardo.
configuratore

Più pertinente a questa risposta: Eric, stai riferendo il richiedente a Contratti di codice, ma sono dolorosamente incompleti; qualsiasi cosa diversa dai contratti più elementari non è applicabile dal controllore statico. Ho provato a usare Code Contract su un piccolo progetto; Ho aggiunto centinaia di righe per ogni metodo specificando tutto ciò che potevo su input e output, eppure, ho dovuto aggiungere così tante Assumechiamate, per casi come membri di array o di enumerazione. Dopo aver aggiunto tutto e aver visto il disastro verificato staticamente che avevo, sono tornato al controllo del codice sorgente perché riduceva la qualità del mio progetto.
configuratore

17
@configurator: sono incompleti perché non possono essere completi; la verifica statica del programma con contratti arbitrari equivale a risolvere il problema di interruzione. (Ad esempio, potresti scrivere un contratto di codice che dice che gli argomenti di un metodo devono essere un controesempio all'ultimo teorema di Fermat; ma il verificatore statico non sarà in grado di verificare che non ci siano tali argomenti.) devi usarlo con giudizio se ti aspetti che il verificatore statico completi il ​​suo lavoro prima della morte per calore dell'universo. (Se il tuo reclamo è che il BCL non è sufficientemente annotato: sono d'accordo.)
Eric Lippert

2
Mi aspetto che si renda conto che quando un metodo promette che l'array o l'enumerazione dei risultati non contiene null, il metodo using può utilizzare i valori in punti che non consentono valori null. Questa è l'unica cosa che mi aspettavo che facesse, ma non era troppo importante per essere utilizzabile senza di essa; qualsiasi altra cosa è solo un bonus. Detto questo, so che la verifica statica non può essere completa, motivo per cui penso che non sia una buona alternativa su cui fare affidamento per i contratti.
configuratore

9
+1 per "Beh, sono contento che ti piaccia." E anche tutte le altre cose.
Robert S.

235

inserisci qui la descrizione dell'immagine

Quindi, in questo esempio, PowerSocket non conosce nient'altro sugli altri oggetti. Tutti gli oggetti dipendono dalla potenza fornita da PowerSocket, quindi implementano IPowerPlug e così facendo possono connettersi ad esso.

Le interfacce sono utili perché forniscono contratti che gli oggetti possono usare per lavorare insieme senza bisogno di sapere altro l'uno dell'altro.


4
L'oggetto in basso a sinistra non sembra implementare IPowerPlug =)
Steven Striga

100
Dannazione, ma dovremo utilizzare un modello di adattatore per utilizzare IPowerPlug in diversi paesi!
Steven Jeuris,

Jerry-rigging di un dispositivo per aggirare l'interfaccia non è sicuro (ma alcune persone lo fanno ancora citando spesso le prestazioni come una scusa non testata) e probabilmente causeranno incendi.
Young John

4
Questa risposta è semplicemente incredibile ...
Mario Garcia,

Il solo fatto di sottolineare questa risposta non dice - in questo esempio particolare - perché usare un'interfaccia sarebbe preferibile all'eredità. Qualcuno che non conosce interfacce potrebbe chiedersi perché non ereditano tutti, ad esempio, da MainsPoweredDevice che fornisce tutte le funzionalità della spina, con la presa che accetta qualsiasi cosa derivata da MainsPoweredDevice.
ingrediente_15939

145

Oltre a fornire le firme della funzione, non fanno nulla. Se riesco a ricordare i nomi e la firma delle funzioni che devono essere implementate, non ce n'è bisogno

Il punto di interfaccia non è aiutarti a ricordare quale metodo implementare, è qui per definire un contratto . Nell'esempio di P.Brian.Mackey foreach (che risulta essere sbagliato , ma non ci interessa), IEnumerable definisce un contratto tra foreach e qualsiasi cosa enumerabile. Dice: "Chiunque tu sia, finché ti atterrai al contratto (implementa IEnumerable), ti prometto che passerò in rassegna tutti i tuoi elementi". E questo è fantastico (per un linguaggio non dinamico).

Grazie alle interfacce è possibile ottenere un accoppiamento molto basso tra due classi.



Non mi piace usare il termine "digitando anatra" perché significa cose diverse per persone diverse. Utilizziamo il pattern matching per il ciclo "foreach" perché quando è stato progettato, IEnumerable <T> non era disponibile. Usiamo la corrispondenza dei modelli per LINQ perché il sistema di tipo C # è troppo debole per catturare il "modello di monade" di cui abbiamo bisogno; avresti bisogno di qualcosa come il sistema di tipi Haskell.
Eric Lippert,

@Eric: la "corrispondenza dei modelli" non ha lo stesso problema? Quando lo sento penso a F # / Scala / Haskell. Ma immagino sia un'idea più ampia della battitura a papera.
Daniel,

@Daniel: Sì, suppongo che lo sia. Sono le sei e mezza e mezza dozzine dell'altra!
Eric Lippert,

36

Le interfacce sono il modo migliore per mantenere costrutti ben disaccoppiati.

Quando scrivi i test, scoprirai che le classi concrete non funzioneranno nel tuo ambiente di test.

Esempio: si desidera testare una classe che dipende da una classe del servizio di accesso ai dati . Se quella classe sta parlando con un servizio web o un database, il test unitario non verrà eseguito nell'ambiente di test (inoltre è diventato un test di integrazione).

Soluzione? Utilizzare un interfaccia per il Data Access servizio e Mock che l'interfaccia in modo da poter testare la classe come unità.

D'altra parte, WPF e Silverlight non giocano affatto con le interfacce quando si tratta di rilegatura. Questa è una ruga piuttosto brutta.


2
senti senti! Le interfacce sono state inventate per risolvere altri problemi, come il polimorfismo. Tuttavia, per me, entrano in gioco quando attuano un modello di iniezione di dipendenza.
Andy,

29

Le interfacce sono la spina dorsale del polimorfismo (statico)! L'interfaccia è ciò che conta. L'ereditarietà non funzionerebbe senza interfacce, in quanto le sottoclassi ereditano sostanzialmente l'interfaccia già implementata del genitore.

Quanto spesso li usi e cosa ti fa fare ??

Abbastanza spesso. Tutto ciò che deve essere collegabile è un'interfaccia nelle mie applicazioni. Spesso hai classi non correlate che devono fornire lo stesso comportamento. Non è possibile risolvere tali problemi con l'ereditarietà.

Hai bisogno di algoritmi diversi per eseguire operazioni sugli stessi dati? Usa un'interfaccia ( vedi schema di strategia )!

Vuoi utilizzare diverse implementazioni di elenchi? Codice contro un'interfaccia e il chiamante non deve preoccuparsi dell'implementazione!

È stato considerato una buona pratica (non solo in OOP) codificare le interfacce per anni, per un solo motivo: è facile cambiare un'implementazione quando ti rendi conto che non soddisfa le tue esigenze. È piuttosto ingombrante se si tenta di ottenerlo solo con eredità multipla o si riduce a creare classi vuote al fine di fornire l'interfaccia necessaria.


1
Mai sentito parlare di polimorfismo, vuoi dire polimorfismo?
Steven Jeuris,

1
detto questo, se microsoft avesse permesso l'ereditarietà multipla in primo luogo, non ci sarebbe stato motivo di esistenza di interfacce
Pankaj Upadhyay,

10
@Pankaj Upadhyay: eredità multipla e interfacce sono due diverse paia di scarpe. Cosa succede se hai bisogno di un'interfaccia di due classi non correlate con comportamenti diversi? Non puoi risolverlo per eredità multipla. DEVI implementarlo separatamente comunque. E poi avrai bisogno di qualcosa per descrivere l'interfaccia al fine di fornire un comportamento polimorfico. L'eredità multipla è un vicolo cieco per camminare in molti casi, ed è troppo facile spararsi nel piede prima o poi.
Falcon,

1
Semplifichiamo. Se la mia interfaccia implementa due funzioni Display e Comment, e ho una classe che le implementa. Allora perché non rimuovo l'interfaccia e utilizzo direttamente le funzioni. Quello che sto dicendo è che ti stanno semplicemente fornendo i nomi delle funzioni che devono essere implementate. Se uno riesce a ricordare quelle funzioni, allora perché creare un'interfaccia
Pankaj Upadhyay,

9
@Pankaj, se questo è tutto ciò di cui hai bisogno per l'interfaccia, non usarla. Usi un'interfaccia quando hai un programma che vuole ignorare ogni aspetto della classe e accedervi dal suo Tipo di base, cioè l'interfaccia. Non hanno bisogno di conoscere nessuna delle sottoclassi, solo che è del tipo di interfaccia. Pertanto, è possibile chiamare il metodo implementato della sottoclasse tramite il riferimento all'interfaccia dell'oggetto. Questa è eredità di base e roba di design. Senza di esso, potresti anche usare C. Anche se non lo usi esplicitamente, il framework non funzionerebbe senza di esso.
Jonathan Henson,

12

Probabilmente l'hai usato foreache lo hai trovato uno strumento di iterazione piuttosto utile. Sapevi che richiede un'interfaccia per funzionare, IEnumerable ?

Questo è certamente un caso concreto che parla dell'utilità di un'interfaccia.


5
In realtà, foreach non richiede IEnumerable: msdn.microsoft.com/en-us/library/9yb8xew9%28VS.80%29.aspx
Matt H

1
Ho studiato tutto questo, ma è come tenere l'orecchio con l'altra mano. Se fosse consentita l'ereditarietà multipla, l'interfaccia sarebbe stata una scelta lontana.
Pankaj Upadhyay,

2
Le interfacce SONO eredità multiple, qualcosa che viene spesso dimenticato. Tuttavia, non consentono l'ereditarietà multipla di comportamento e stato. Mixin o tratti consentono l'ereditarietà multipla del comportamento, ma non lo stato condiviso che causa problemi: en.wikipedia.org/wiki/Mixin
Matt H

@Pankaj, offtopico, ma ti dispiace se ti chiedo qual è la tua lingua madre? "Tenere l'orecchio con l'altra mano" è un grande linguaggio ed ero curioso di sapere da dove viene.
Kevin,

3
@Uomo di ghiaccio. LOL .... Vengo dall'India. Ed ecco un linguaggio comune che riflette nel fare le cose facili nel modo più difficile.
Pankaj Upadhyay,

11

Le interfacce sono per codificare oggetti come una spina è per il cablaggio domestico. Salderesti la radio direttamente al cablaggio di casa? E il tuo aspirapolvere? Ovviamente no. La spina e la presa in cui si inserisce formano l '"interfaccia" tra il cablaggio di casa e il dispositivo che necessita dell'alimentazione da esso. Il cablaggio della tua casa non deve sapere nulla del dispositivo se non quello di utilizzare una spina con messa a terra a tre poli e richiede energia elettrica a 120 V CA <= 15 A. Al contrario, il dispositivo non richiede alcuna conoscenza arcana di come è cablata la tua casa, a parte il fatto che ha una o più prese a tre poli posizionate in modo conveniente che forniscono 120VAC <= 15A.

Le interfacce svolgono una funzione molto simile nel codice. Un oggetto può dichiarare che una particolare variabile, parametro o tipo restituito è di un tipo di interfaccia. L'interfaccia non può essere istanziata direttamente con una newparola chiave, ma il mio oggetto può essere fornito o trovare l'implementazione di quell'interfaccia con cui dovrà funzionare. Una volta che l'oggetto ha la sua dipendenza, non deve sapere esattamente cos'è quella dipendenza, deve solo sapere che può chiamare i metodi X, Y e Z sulla dipendenza. Le implementazioni dell'interfaccia non devono sapere come verranno utilizzate, devono solo sapere che dovranno fornire ai metodi X, Y e Z firme particolari.

Pertanto, astrattando più oggetti dietro la stessa interfaccia, si fornisce un insieme comune di funzionalità a qualsiasi consumatore di oggetti di tale interfaccia. Non è necessario sapere che l'oggetto è, ad esempio, un elenco, un dizionario, un elenco di collegamenti, un elenco di ordini o altro. Poiché sai che tutti questi sono IEnumerables, puoi utilizzare i metodi di IEnumerable per esaminare ogni elemento di queste raccolte uno alla volta. Non devi sapere che una classe di output è ConsoleWriter, FileWriter, NetworkStreamWriter o persino MulticastWriter che accetta altri tipi di writer; tutto quello che devi sapere è che sono tutti IWriter (o qualsiasi altra cosa), e quindi hanno un metodo "Write" in cui puoi passare una stringa e quella stringa verrà emessa.


7

Mentre è chiaramente un piacere per il programmatore (almeno all'inizio) avere l'ereditarietà multipla, questa è un'omissione quasi banale e non dovresti (nella maggior parte dei casi) fare affidamento sull'ereditarietà multipla. Le ragioni sono complesse, ma se vuoi davvero conoscerlo, considera l'esperienza dei due più famosi linguaggi di programmazione (per indice TIOBE ) che la supportano: C ++ e Python (rispettivamente 3 ° e 8 °).

In Python, l'ereditarietà multipla è supportata, ma è quasi universalmente fraintesa dai programmatori e affermare che sai come funziona, significa leggere e comprendere questo documento sull'argomento: Metodo di risoluzione dell'ordine . Qualcos'altro, che è accaduto in Python, è che le interfacce hanno un po 'il linguaggio - Zope.Interfaces.

Per C ++, google "gerarchia dei diamanti C ++" ed ecco la bruttezza che sta per coprirti. I professionisti del C ++ sanno come utilizzare l'ereditarietà multipla. Tutti gli altri di solito giocano solo senza sapere quali saranno i risultati. Un'altra cosa che mostra quanto siano utili le interfacce è il fatto che in molti casi una classe potrebbe aver bisogno di sovrascrivere completamente il comportamento dei suoi genitori. In tali casi, l'implementazione del genitore non è necessaria e solo carica la classe figlio con la memoria per le variabili private del genitore, che potrebbe non avere importanza nell'era C #, ma importa quando si esegue la programmazione integrata. Se si utilizza un'interfaccia, quel problema è inesistente.

In conclusione, le interfacce sono, a mio avviso, una parte essenziale di OOP, perché applicano un contratto. L'ereditarietà multipla è utile in casi limitati e di solito solo ai ragazzi che sanno come usarla. Quindi, se sei un principiante, sei colui che è trattato dalla mancanza di eredità multipla - questo ti dà una migliore possibilità di non sbagliare .

Inoltre, storicamente, l'idea di un'interfaccia è radicata molto prima delle specifiche di progettazione C # di Microsoft. La maggior parte delle persone considera C # come un aggiornamento su Java (nella maggior parte dei sensi) e indovina da dove C # ha ottenuto le sue interfacce: Java. Protocollo è una parola più vecchia per lo stesso concetto ed è molto più vecchia di .NET.

Aggiornamento: ora vedo che avrei potuto rispondere a una domanda diversa: perché le interfacce invece l'ereditarietà multipla, ma questa sembrava la risposta che stavi cercando. Inoltre una lingua OO dovrebbe avere almeno una delle due e le altre risposte hanno coperto la tua domanda originale.


6

È difficile per me immaginare un codice C # pulito e orientato agli oggetti senza l'uso di interfacce. Li usi ogni volta che desideri imporre la disponibilità di determinate funzionalità senza forzare le classi a ereditare da una classe base specifica e ciò consente al tuo codice di avere il livello rilevante di accoppiamento (basso).

Non sono d'accordo sul fatto che l'ereditarietà multipla sia meglio che avere interfacce, anche prima di iniziare a sostenere che l'ereditarietà multipla provenga da un suo insieme di dolori. Le interfacce sono uno strumento di base per consentire il polimorfismo e il riutilizzo del codice, cosa si può volere di più?


5

Personalmente adoro la classe astratta e la uso più di un'interfaccia. La differenza principale sta nell'integrazione con interfacce .NET come IDisposable, IEnumerable e così via ... e con interoperabilità COM. Inoltre, l'interfaccia richiede un po 'meno sforzo di scrittura rispetto a una classe astratta e una classe può implementare più di un'interfaccia mentre può ereditare solo da una classe.

Detto questo, trovo che la maggior parte delle cose per cui utilizzerei un'interfaccia sono meglio servite da una classe astratta. Le funzioni virtuali pure - funzioni astratte - consentono di forzare un implementatore a definire una funzione simile al modo in cui un'interfaccia forza un implementatore a definire tutti i suoi membri.

Tuttavia, in genere si utilizza un'interfaccia quando non si desidera imporre un determinato design alla super classe, mentre si utilizza una classe astratta per avere un design riutilizzabile che è già in gran parte implementato.

Ho ampiamente utilizzato le interfacce con la scrittura di ambienti plugin usando lo spazio dei nomi System.ComponentModel. Sono molto utili.


1
Molto ben messo! Immagino che ti piacerà il mio articolo sulle lezioni astratte. L'astrazione è tutto .
Steven Jeuris,

5

Posso dire che mi riferisco a quello. Quando ho iniziato a conoscere OO e C #, anche io non avevo interfacce. Va bene. Dobbiamo solo imbatterci in qualcosa che ti farà apprezzare le comodità delle interfacce.

Vorrei provare due approcci. E scusami per le generalizzazioni.

Prova 1

Di 'che sei un madrelingua inglese. Vai in un altro paese in cui l'inglese non è la lingua madre. Avete bisogno di aiuto. Hai bisogno di qualcuno che ti possa aiutare.

Chiedete: "Ehi, sei nato negli Stati Uniti?" Questa è eredità.

Oppure chiedi: "Ehi, parli inglese"? Questa è interfaccia.

Se ti preoccupi di ciò che fa, puoi fare affidamento sulle interfacce. Se ti interessa ciò che è, fai affidamento sull'eredità.

Va bene fare affidamento sull'eredità. Se hai bisogno di qualcuno che parli inglese, che ami il tè e che ami il calcio, ti conviene servire un inglese. :)

Prova 2

Ok, proviamo un altro esempio.

Utilizzi database diversi e devi implementare classi astratte per lavorare con essi. Passerai la tua classe a una classe dal fornitore DB.

public abstract class SuperDatabaseHelper
{
   void Connect (string User, string Password)
}

public abstract class HiperDatabaseHelper
{
   void Connect (string Password, string User)
}

Eredità multipla, dici? Prova con il caso sopra. Non puoi. Il compilatore non saprà quale metodo Connect stai tentando di chiamare.

interface ISuperDatabaseHelper
{
  void Connect (string User, string Password)
}

interface IHiperDatabaseHelper
{
   void Connect (string Password, string User)
}

Ora, c'è qualcosa con cui possiamo lavorare - almeno in C # - dove possiamo implementare esplicitamente le interfacce.

public class MyDatabaseHelper : ISuperDatabaseHelper, IHiperDatabaseHelper
{
   IHiperDataBaseHelper.Connect(string Password, string User)
   {
      //
   }

   ISuperDataBaseHelper.Connect(string User, string Password)
   {
      //
   }

}

Conclusione

Gli esempi non sono i migliori, ma penso che ottenga il punto.

"Otterrai" interfacce solo quando ne avrai bisogno. Fino a quando penserai che non sono per te.


Il primo tentativo è quello che ha dato il mio voto.
Osundblad,

1
Da ora in poi userò totalmente l'analogia tra il parlante americano e quello inglese. È fantastico.
Bryan Boettcher,

Spiegato in modo più semplice! Fantastico.
Aimal Khan,

4

Ci sono 2 motivi principali:

  1. Mancanza di eredità multipla. È possibile ereditare da una classe base e implementare un numero qualsiasi di interfacce. Questo è l'unico modo per "fare" l'ereditarietà multipla in .NET.
  2. Interoperabilità COM. Tutto ciò che dovrà essere utilizzato dalle tecnologie "più vecchie" dovrà avere interfacce definite.

Il punto 1 è sicuramente il motivo e il motivo sviluppato dagli stessi sviluppatori Microsoft
Pankaj Upadhyay,

1
@Pankja In realtà, hanno preso l'idea dell'interfaccia da Java (come una buona parte delle funzionalità di C #).
Oliver Weiler,

3

L'uso di interfacce aiuta un sistema a rimanere disaccoppiato e quindi più facile da refactoring, modifica e ridistribuzione. È un concetto fondamentale dell'ortodossia orientata agli oggetti e l'ho appreso per la prima volta quando i guru del C ++ hanno creato "classi astratte pure" che sono abbastanza equivalenti alle interfacce.


Il disaccoppiamento è importante perché mantiene diversi componenti di un sistema indipendenti l'uno dall'altro. Che anche le modifiche di grande impatto in un componente non si propagano ad altri componenti. Pensa alle spine di alimentazione come a un'interfaccia per la tua azienda (specificando la tensione, i pin fisici e il formato della spina). Grazie a questa interfaccia, l'utilità può cambiare completamente il modo in cui producono energia (ad es. Utilizzare la tecnologia solare), ma nessuno dei dispositivi noterà nemmeno il cambiamento.
miraculixx,

3

Le interfacce da sole non sono molto utili. Ma quando implementato da classi concrete, si vede che ti dà la flessibilità di avere una o più implementazioni. Il vantaggio è che l'oggetto che utilizza l'interfaccia non ha bisogno di sapere come vanno i dettagli dell'implementazione effettiva, che si chiama incapsulamento.


2

Sono principalmente utilizzati per la riusabilità del codice. Se si codifica per l'interfaccia, è possibile utilizzare una classe diversa che eredita da tale interfaccia e non interrompere tutto.

Inoltre sono molto utili nei servizi web in cui si desidera far sapere al cliente cosa fa una classe (in modo che possano consumarla) ma non si vuole dare loro il codice attuale.


2

Come giovane programmatore / sviluppatore, solo imparando C # potresti non vedere l'utilità dell'interfaccia, perché potresti scrivere i tuoi codici usando le tue classi e il codice funziona bene, ma nello scenario di vita reale, la creazione di un'applicazione scalabile, solida e gestibile implica l'utilizzo alcuni modelli e architetture, che possono essere resi possibili solo tramite l'interfaccia, ad esempio è l'iniezione di dipendenza.


1

Un'implementazione nel mondo reale:

È possibile eseguire il cast di un oggetto come tipo di interfaccia:

IHelper h = (IHelper)o;
h.HelperMethod();

È possibile creare un elenco di un'interfaccia

List<IHelper> HelperList = new List<IHelper>();

Con questi oggetti è possibile accedere a qualsiasi metodo o proprietà dell'interfaccia. In questo modo è possibile definire un'interfaccia per la parte di un programma. E costruisci la logica attorno ad esso. Quindi qualcun altro può implementare la tua interfaccia nei suoi oggetti Business. Se il BO cambia, possono cambiare la logica per i componenti dell'interfaccia e non richiedere una modifica alla logica per il tuo pezzo.


0

Le interfacce si prestano alla modularità in stile plug-in fornendo un meccanismo che consente alle classi di comprendere (e sottoscrivere) alcuni tipi di messaggi che il sistema recapita. Elaborerò.

Nella tua applicazione, decidi che ogni volta che un modulo viene caricato o ricaricato, vuoi che tutte le cose che ospita vengano cancellate. Definisci IClearun'interfaccia che implementa Clear. Inoltre, decidi che ogni volta che l'utente preme il pulsante Salva, il modulo dovrebbe tentare di mantenere il suo stato. Pertanto, tutto ciò che rimane ISavericeve un messaggio per persistere nel suo stato. Naturalmente, praticamente parlando, la maggior parte delle interfacce gestisce diversi messaggi.

Ciò che distingue le interfacce è che il comportamento comune può essere raggiunto senza ereditarietà. La classe che implementa una determinata interfaccia capisce semplicemente come comportarsi quando viene emesso un comando (un messaggio di comando) o come rispondere quando viene eseguita una query (un messaggio di query). In sostanza, le classi nella tua applicazione comprendono i messaggi forniti dalla tua applicazione. Ciò semplifica la costruzione di un sistema modulare in cui le cose possono essere collegate.

Nella maggior parte delle lingue ci sono meccanismi (come LINQ ) per interrogare cose che rispettano un'interfaccia. Questo di solito ti aiuterà ad eliminare la logica condizionale perché non dovrai dire cose dissimili (che non sono necessariamente derivate dalla stessa catena di eredità) come comportarti in modo simile (secondo un messaggio particolare). Invece, raccogli tutto ciò che comprende un determinato messaggio (rispetta un'interfaccia) e pubblichi il messaggio.

Ad esempio, potresti sostituire ...

Me.PublishDate.Clear()
Me.Subject.Clear()
Me.Body.Clear()

...con:

For Each ctl As IClear In Me.Controls.OfType(Of IClear)()
    ctl.Clear()
Next

Che suona davvero molto simile a:

Ascolta, senti! Tutti quelli che capiscono la compensazione, per favore Clearadesso!

In questo modo, possiamo programmaticamente evitare di dire a ogni cosa di cancellarsi. E quando in futuro verranno aggiunti elementi clearable, essi risponderanno semplicemente senza alcun codice aggiuntivo.


0

Quanto segue è pseudocodice:

class MyClass{

    private MyInterface = new MyInterfaceImplementationB();

    // Code using Thingy 

}

interface MyInterface{

    myMethod();

}

class MyInterfaceImplementationA{ myMethod(){ // method implementation A } }

class MyInterfaceImplementationB{ myMethod(){ // method implementation B } }

class MyInterfaceImplementationC{ myMethod(){ // method implementation C } }

Le ultime classi possono essere implementazioni completamente diverse.

A meno che l'ereditarietà multipla non sia possibile, l'ereditarietà impone l'implementazione della classe genitore rendendo le cose più rigide. La programmazione contro le interfacce, d'altra parte, può consentire al codice o ad un framework di essere estremamente flessibili. Se ti capita mai di imbatterti in un caso in cui desideri poter scambiare le lezioni in una catena ereditaria, capirai perché.

Ad esempio, un framework che fornisce un Reader originariamente destinato a leggere i dati dal disco potrebbe essere implementato per fare qualcosa della stessa natura ma in un modo completamente diverso. Ad esempio interpretare il codice Morse per esempio.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.