wake-up-neo.net

Come faccio a sapere quando creare un'interfaccia?

Sono a un certo punto del mio sviluppo e sto imparando dove sento di dover imparare di più sulle interfacce.

Leggo spesso su di loro ma sembra proprio che non riesca a coglierli.

Ho letto esempi come: Animal base class, con interfaccia IAnimal per cose come 'Walk', 'Run', 'GetLegs', ecc. - Ma non ho mai lavorato su qualcosa e mi sono sentito come "Ehi, dovrei usare un'interfaccia Qui!"

Cosa mi sto perdendo? Perché è un concetto così difficile da afferrare! Sono solo intimidito dal fatto che potrei non rendermi mai conto di una necessità concreta per uno, principalmente a causa di un aspetto mancante della loro comprensione! Mi fa sentire che mi manca qualcosa in alto in termini di essere uno sviluppatore! Se qualcuno ha avuto un'esperienza come questa e ha avuto una svolta, apprezzerei alcuni consigli su come comprendere questo concetto. Grazie.

189
user53885

risolve questo problema concreto:

hai a, b, c, d di 4 tipi diversi. in tutto il codice hai qualcosa come:

a.Process();
b.Process();
c.Process();
d.Process();

perché non li hanno implementare IProcessable e quindi farlo

List<IProcessable> list;

foreach(IProcessable p in list)
    p.Process();

questo ridimensionerà molto meglio quando aggiungi, diciamo, 50 tipi di classi che fanno tutte la stessa cosa.


Un altro problema concreto:

Hai mai dato un'occhiata a System.Linq.Enumerable? Definisce una tonnellata di metodi di estensione che operano su qualsiasi tipo che implementa IEnumerable. Poiché tutto ciò che implementa IEnumerable in pratica dice "I iteration in un modello di tipo foreach non ordinato", è possibile definire comportamenti complessi (Count, Max, Where, Select, ecc.) Per qualsiasi tipo enumerabile.

146
Jimmy

Mi piace molto la risposta di Jimmy, ma sento di dover aggiungere qualcosa. La chiave di tutto è la "capacità" in IProcess capace. Indica una capacità (o proprietà, ma significa "qualità intrinseca", non nel senso delle proprietà C #) dell'oggetto che implementa l'interfaccia. IAnimal probabilmente non è un buon esempio per un'interfaccia, ma IWalkable potrebbe essere una buona interfaccia da avere se il tuo sistema ha molte cose che possono camminare. Potresti avere classi derivate da animali come cane, mucca, pesce, serpente. I primi due probabilmente implementeranno IWalkable, gli ultimi due non camminano, quindi non lo farebbero. Ora chiedi "perché non avere un'altra superclasse, WalkingAnimal, da cui derivano Dog e Cow?". La risposta è quando hai qualcosa di completamente fuori dall'albero dell'eredità che può anche camminare, come un robot. Il robot implementerebbe IWalkable, ma probabilmente non deriverebbe da Animal. Se vuoi un elenco di cose che possono camminare, lo digiti come IWalkable e puoi mettere tutti gli animali che camminano più i robot nell'elenco.

Ora sostituisci IWalkable con qualcosa di più software come IPersistable, e l'analogia diventa molto più vicina a ciò che vedresti in un vero programma.

129
rmeador

Utilizzare le interfacce quando le implementazioni della stessa funzionalità differiranno.

Utilizzare una classe astratta/base quando è necessario condividere un'implementazione concreta comune.

70
Element

Pensa a un'interfaccia come a un contratto. È un modo per dire "Queste classi dovrebbero seguire questo insieme di regole".

Quindi, nell'esempio IAnimal, è un modo per dire "DEVO essere in grado di chiamare Run, Walk, ecc. Su classi che implementano IAnimal."

Perché è utile? Potresti voler creare una funzione che si basa sul fatto che devi essere in grado di chiamare Run and Walk, ad esempio, sull'oggetto. Potresti avere quanto segue:

public void RunThenWalk(Monkey m) {
    m.Run();
    m.Walk();
}

public void RunThenWalk(Dog d) {
    d.Run();
    d.Walk();
}

... e ripeterlo per tutti gli oggetti che conosci possono correre e camminare. Tuttavia, con la tua interfaccia IAnimal, puoi definire la funzione una volta come segue:

public void RunThenWalk(IAnimal a) {
    a.Run();
    a.Walk();
}

Programmando contro l'interfaccia, in sostanza ti fidi delle classi per implementare l'intento dell'interfaccia. Quindi nel nostro esempio, il pensiero è "Non mi interessa come corrono e camminano, purché corrano e camminano. Il mio RunThenWalk sarà valido fintanto che rispettano tale accordo. Funziona perfettamente senza conoscere nient'altro sulla classe. "

C'è anche una buona discussione in questa domanda correlata .

32
Larsenal

Non preoccuparti così tanto. Molti sviluppatori dovranno raramente scrivere un'interfaccia. Utilizzerai frequentemente le interfacce disponibili all'interno del framework . NET , ma se non senti la necessità di scriverne una in qualunque momento presto non c'è nulla di sorprendente.

L'esempio che do sempre a qualcuno è se hai una classe di barche a vela e una classe Viper. Ereditano rispettivamente la classe Boat e la classe Car. Ora dì che devi scorrere tutti questi oggetti e chiamare il loro metodo Drive(). Mentre potresti scrivere del codice come il seguente:

if(myObject is Boat)
    ((Boat)myObject).Drive()
else
    if (myObject is Car)
        ((Car)myObject).Drive()

Sarebbe molto più semplice scrivere:

((IDrivable)myObject).Drive()
18
Spencer Ruport

Jimmy ha ragione, quando vuoi essere in grado di usare una singola variabile per più tipi, ma tutti questi tipi implementano lo stesso metodo tramite una dichiarazione di interfaccia. Quindi puoi chiamarli metodo principale sulla variabile digitata dall'interfaccia.

C'è un secondo motivo per usare le interfacce, comunque. Quando l'architetto di progetto è una persona diversa rispetto al programmatore di implementazione, oppure esistono diversi programmatori di implementazione e un project manager. Il responsabile può scrivere un sacco di interfacce e vedere che il sistema interagisce, quindi lasciare agli sviluppatori il compito di compilare le interfacce con le classi di implementazione. Questo è il modo migliore per garantire a più persone di scrivere classi compatibili e possono farlo in parallelo.

16
Karl

Mi piace l'analogia dell'esercito.

Al sergente non importa se sei un sviluppatore di software, musicista o avvocato.
Sei trattato come soldato.

uml

È più facile per il sergente non preoccuparsi dei dettagli specifici delle persone con cui sta lavorando,
tratta tutti come astrazioni di soldato (... e puniscili quando non riescono a comportarsi come quelli).

La capacità delle persone di agire come soldati si chiama polimorfismo.

Le interfacce sono costruzioni software che aiutano a raggiungere il polimorfismo.

Necessità di astrarre i dettagli per raggiungere la semplicità è la risposta alla tua domanda.

Polimorfismo , che etimologicamente significa "molte forme", è la capacità di trattare un oggetto di qualsiasi sottoclasse di una classe base come se fosse un oggetto della classe base. Una classe base ha quindi molte forme: la classe base stessa e una delle sue sottoclassi.

(..) Ciò semplifica la scrittura del codice e la comprensione da parte degli altri. Inoltre rende il tuo codice estensibile, perché altre sottoclassi potrebbero essere aggiunte in seguito alla famiglia di tipi e anche gli oggetti di quelle nuove sottoclassi funzionerebbero con il codice esistente.

15
Arnis Lapsa

Nella mia esperienza, la forza trainante per creare interfacce non si è verificata fino a quando non ho iniziato a fare test unitari con un framework beffardo. È diventato abbondantemente chiaro che l'uso delle interfacce avrebbe reso molto più semplice il derisione (poiché il framework dipendeva dal fatto che i metodi fossero virtuali). Una volta iniziato, ho visto il valore di sottrarre l'interfaccia alla mia classe dall'implementazione. Anche se non creo un'interfaccia reale, provo ora a rendere virtuali i miei metodi (fornendo un'interfaccia implicita che può essere ignorata).

Ci sono molte altre ragioni che ho scoperto per rafforzare la buona pratica del refactoring delle interfacce, ma la cosa test/derisione dell'unità era ciò che ha fornito il "momento aha" iniziale dell'esperienza pratica.

EDIT : Per chiarire, con unit testing e beffardo ho sempre due implementazioni: l'implementazione reale, concreta e un'implementazione fittizia alternativa utilizzata nei test. Una volta che hai due implementazioni, il valore dell'interfaccia diventa evidente: gestiscilo in termini di interfaccia in modo da poter sostituire l'implementazione in qualsiasi momento. In questo caso lo sto sostituendo con un'interfaccia finta. So che posso farlo senza un'interfaccia reale se la mia classe è costruita correttamente, ma l'uso di un'interfaccia reale lo rinforza e lo rende più pulito (più chiaro per il lettore). Senza questo slancio, non credo che avrei apprezzato il valore delle interfacce poiché solo la maggior parte delle mie classi ha mai avuto un'unica implementazione concreta.

14
tvanfosson

Alcuni esempi non di programmazione che potrebbero aiutarti a vedere gli usi appropriati delle interfacce nella programmazione.

C'è un'interfaccia tra i dispositivi elettrici e la rete elettrica: è il insieme di convenzioni sulla forma delle spine e delle prese e le tensioni/correnti che li attraversano. Se desideri implementare un nuovo dispositivo elettrico, purché la tua spina segua le regole, sarà in grado di ottenere servizi dalla rete. Questo rende estensibilità molto semplice e rimuove o riduce i costi di coordinamento: non è necessario informare il fornitore di energia elettrica su come funziona il nuovo dispositivo e raggiungere un accordo separato su come collegare il nuovo dispositivo alla rete.

I paesi hanno spessori ferroviari standard. Ciò consente una divisione del lavoro tra le società di ingegneria che mettono giù Rails e le società di ingegneria che costruiscono treni per correre su quelle Rails, e rende possibile per le compagnie ferroviarie sostituisci e aggiorna treni senza ricertificare l'intero sistema.

Il servizio che un'azienda presenta ad un cliente può essere descritto come un'interfaccia: un'interfaccia ben definita enfatizza il servizio e nasconde i mezzi. Quando metti una lettera in una casella di posta, ti aspetti che il sistema postale consegni la lettera entro un determinato tempo, ma non hai aspettative su come la lettera viene recapitata: non devi sapere, e il servizio postale ha flessibilità nella scelta dei mezzi della consegna che soddisfa meglio i requisiti e le circostanze attuali. Un'eccezione a ciò è la capacità dei clienti di scegliere la posta aerea: non è il tipo di interfaccia che un moderno programmatore di computer avrebbe progettato, poiché rivela troppa implementazione.

Esempi dalla natura: non mi piacciono troppo gli esempi di eats (), makesSound (), move (), ecc. Descrivono il comportamento, che è corretto, ma non descrivono le interazioni e come sono abilitate. Gli esempi ovvi di interfacce che consentono interazioni in natura hanno a che fare con la riproduzione, ad esempio un fiore fornisce una certa interfaccia a un'ape in modo che possa avvenire l'impollinazione.

10
user8599

Un esempio di codice (combinazione di Andrew's con un mio extra in what-is-the-purpose-of-interfaces ), che spiega anche perché l'interfaccia invece di una classe astratta su linguaggi senza supporto per ereditarietà multipla (c # e Java):

interface ILogger
{
    void Log();
}
class FileLogger : ILogger
{
    public void Log() { }
}
class DataBaseLogger : ILogger
{
    public void Log() { }
}
public class MySpecialLogger : SpecialLoggerBase, ILogger
{
    public void Log() { }
}

Si noti che FileLogger e DataBaseLogger non necessitano dell'interfaccia (potrebbe essere una classe base astratta Logger). Ma considera che ti viene richiesto di usare un logger di terze parti che ti costringe a usare una classe base (diciamo che espone metodi protetti che devi usare). Poiché il linguaggio non supporta l'ereditarietà multipla, non sarà possibile utilizzare l'approccio di classe base astratto.

La linea di fondo è: utilizzare un'interfaccia quando possibile per ottenere una maggiore flessibilità sul codice. L'implementazione è meno vincolata, quindi si adatta meglio al cambiamento.

5
eglasius

È del tutto possibile andare avanti per tutta la vita come sviluppatore .net e non scrivere mai le tue interfacce. Dopotutto, siamo sopravvissuti bene senza di loro per decenni e le nostre lingue erano ancora complete di Turing.

Non posso dirti perché hai bisogno di interfacce, ma posso darti un elenco di dove li usiamo nel nostro progetto attuale:

  1. Nel nostro modello di plug-in, cariciamo i plug-in per interfaccia e forniamo tale interfaccia a chi scrive i plug-in a cui conformarsi.

  2. Nel nostro sistema di messaggistica intermachine, le classi di messaggi implementano tutte un'interfaccia specifica e vengono "scartate" utilizzando l'interfaccia.

  3. Il nostro sistema di gestione della configurazione definisce un'interfaccia utilizzata per impostare e recuperare le impostazioni di configurazione.

  4. Abbiamo un'interfaccia che usiamo per evitare un brutto problema di riferimento circolare. (Non farlo se non è necessario.)

Immagino che se c'è una regola, è usare le interfacce quando vuoi raggruppare diverse classi all'interno di una relazione is-a, ma non vuoi fornire alcuna implementazione nella classe base.

5
Yes - that Jake.

Di tanto in tanto ho usato le interfacce ed ecco il mio ultimo utilizzo (i nomi sono stati generalizzati):

Ho un sacco di controlli personalizzati su un WinForm che devono salvare i dati sul mio oggetto business. Un approccio consiste nel chiamare ciascun controllo separatamente:

myBusinessObject.Save(controlA.Data);
myBusinessObject.Save(controlB.Data);
myBusinessObject.Save(controlC.Data);

Il problema con questa implementazione è che ogni volta che aggiungo un controllo devo andare nel mio metodo "Salva dati" e aggiungere il nuovo controllo.

Ho modificato i miei controlli per implementare un'interfaccia ISaveable che ha un metodo SaveToBusinessObject (...), quindi ora il mio metodo "Save Data" scorre solo i controlli e se ne trova uno che è ISaveable, chiama SaveToBusinessObject. Quindi ora quando è necessario un nuovo controllo, tutto quello che qualcuno deve fare è implementare ISaveable in quell'oggetto (e non toccare mai un'altra classe).

foreach(Control c in Controls)
{
  ISaveable s = c as ISaveable;

  if( s != null )
      s.SaveToBusinessObject(myBusinessObject);
}

Il vantaggio spesso non realizzato per le interfacce è la localizzazione delle modifiche. Una volta definito, raramente modificherai il flusso complessivo di un'applicazione ma spesso effettuerai modifiche a livello di dettaglio. Quando si mantengono i dettagli in oggetti specifici, una modifica in ProcessA non influirà su una modifica in ProcessB. (Anche le classi di base ti danno questo vantaggio.)

EDIT: un altro vantaggio è la specificità nelle azioni. Come nel mio esempio, tutto ciò che voglio fare è salvare i dati; Non mi interessa che tipo di controllo sia o se possa fare altro: voglio solo sapere se posso salvare i dati nel controllo. Rende il mio codice di salvataggio abbastanza chiaro - non ci sono controlli per vedere se è testo, numerico, booleano o altro perché il controllo personalizzato gestisce tutto ciò.

4
Austin Salonen

Dovresti definire un'interfaccia una volta che devi forzare un comportamento per la tua classe.

Il comportamento di un animale può comportare camminare, mangiare, correre, ecc. Pertanto, si definiscono come interfacce.

Un altro esempio pratico è l'interfaccia ActionListener (o Runnable). Li implementeresti quando devi tenere traccia di un particolare evento. Pertanto, è necessario fornire l'implementazione per il metodo actionPerformed(Event e) nella propria classe (o sottoclasse). Allo stesso modo, per l'interfaccia Runnable, si fornisce l'implementazione per il metodo public void run().

Inoltre, puoi avere queste interfacce implementate da qualsiasi numero di classi.

Un'altra istanza in cui vengono utilizzate le interfacce (in Java) è l'implementazione dell'ereditarietà multipla offerta in C++.

4
Epitaph

Supponiamo che tu voglia voler modellare i fastidi che potrebbero verificarsi quando provi ad andare a dormire.

Modello prima delle interfacce

enter image description here

class Mosquito {
    void flyAroundYourHead(){}
}

class Neighbour{
    void startScreaming(){}
}

class LampJustOutsideYourWindow(){
    void shineJustThroughYourWindow() {}
}

Come vedi chiaramente molte "cose" possono essere fastidiose quando provi a dormire.

Utilizzo di classi senza interfacce

Ma quando si tratta di usare queste classi abbiamo un problema. Non hanno nulla in comune. Devi chiamare ciascun metodo separatamente.

class TestAnnoyingThings{
    void testAnnoyingThinks(Mosquito mosquito, Neighbour neighbour, LampJustOutsideYourWindow lamp){
         if(mosquito != null){
             mosquito.flyAroundYourHead();
         }
         if(neighbour!= null){
             neighbour.startScreaming();
         }
         if(lamp!= null){
             lamp.shineJustThroughYourWindow();
         }
    }
}

Modello con interfacce

Per ovviare a questo problema possiamo introdurre un iterface enter image description here

interface Annoying{
   public void annoy();

}

E implementalo all'interno delle classi

class Mosquito implements Annoying {
    void flyAroundYourHead(){}

    void annoy(){
        flyAroundYourHead();
    }
}

class Neighbour implements Annoying{
    void startScreaming(){}

    void annoy(){
        startScreaming();
    }
}

class LampJustOutsideYourWindow implements Annoying{
    void shineJustThroughYourWindow() {}

    void annoy(){
        shineJustThroughYourWindow();
    }
}

Utilizzo con interfacce

Ciò renderà l'utilizzo di queste classi molto più semplice

class TestAnnoyingThings{
    void testAnnoyingThinks(Annoying annoying){
        annoying.annoy();
    }
}
3
Marcin Szymczak

Se si sfogliano gli assembly .NET Framework e si esegue il drill-down nelle classi di base per uno qualsiasi degli oggetti standard, si noteranno molte interfacce (membri denominati come ISomeName).

Le interfacce sono fondamentalmente per l'implementazione di framework, grandi o piccoli. Mi sono sentito allo stesso modo riguardo alle interfacce fino a quando non ho voluto scrivere un framework tutto mio. Ho anche scoperto che la comprensione delle interfacce mi ha aiutato a imparare i framework molto più rapidamente. Nel momento in cui desideri scrivere una soluzione più elegante per qualsiasi cosa, scoprirai che un'interfaccia ha molto senso. È come un metodo per permettere a una classe di indossare gli abiti appropriati per il lavoro. Ancora più importante, le interfacce consentono ai sistemi di diventare molto più autocompattanti, poiché gli oggetti complessi diventano meno complessi quando la classe implementa le interfacce, il che aiuta a classificare le sue funzionalità.

Le classi implementano interfacce quando vogliono essere in grado di partecipare in modo esplicito o implicito a un framework. Ad esempio, IDisposable è un'interfaccia comune che fornisce la firma del metodo per il metodo Dispose () popolare e utile. In un framework, tutto ciò che tu o un altro sviluppatore dovete sapere su una classe è che se implementa IDisposable, allora sapete che ((IDisposable) myObject) .Dispose () è disponibile per essere chiamato per scopi di pulizia.

ESEMPIO CLASSICO: senza implementare l'interfaccia IDisposable, non è possibile utilizzare il costrutto della parola chiave "using ()" in C #, poiché richiede che qualsiasi oggetto specificato come parametro possa essere implicitamente trasmesso su IDisposable.

ESEMPIO COMPLESSO: Un esempio più complesso sarebbe la classe System.ComponentModel.Component. Questa classe implementa sia IDisposable che IComponent. La maggior parte, se non tutti, gli oggetti .NET a cui è associato un visual designer ad essi implementano IComponent in modo che il IDE sarà in grado di interagire con il componente.

CONCLUSIONE: man mano che acquisisci familiarità con .NET Framework, la prima cosa che farai quando incontrerai una nuova classe nel Browser degli oggetti o nello strumento .NET Reflector (gratuito) ( http://www.red -gate.com/products/reflector/ ) è verificare la classe da cui eredita e anche le interfacce che implementa. .NET Reflector è persino migliore di Object Browser perché ti consente di vedere anche le classi derivate. Ciò ti consente di conoscere tutti gli oggetti che derivano da una determinata classe, quindi potenzialmente conoscere le funzionalità del framework che non sapevi esistessero. Ciò è particolarmente significativo quando vengono aggiunti nuovi spazi dei nomi aggiornati o nuovi a .NET Framework.

Consente inoltre di eseguire test di unità Mock (.Net). Se la tua classe utilizza un'interfaccia, puoi deridere l'oggetto nel test dell'unità e testare facilmente la logica (senza effettivamente colpire il database, il servizio web, ecc.).

http://www.nmock.org/

2
Jobo

L'esempio più semplice da dare è qualcosa come i Processori di pagamento (Paypal, PDS ecc.).

Supponi di creare un'interfaccia IPaymentProcessor con i metodi ProcessACH e ProcessCreditCard.

Ora puoi implementare un'implementazione concreta di Paypal. Fare in modo che questi metodi chiamino le funzioni specifiche di Paypal.

Se decidi in seguito, devi passare a un altro fornitore, puoi farlo. Basta creare un'altra implementazione concreta per il nuovo provider. Poiché tutto ciò a cui sei legato è la tua interfaccia (contratto), puoi scambiare quale utilizza la tua applicazione senza cambiare il codice che la consuma.

2
Jab

Considera di creare un gioco di tiro in prima persona. Il giocatore ha più pistole tra cui scegliere.

Possiamo avere un'interfaccia Gun che definisce una funzione shoot().

Abbiamo bisogno di diverse sottoclassi di Gun class e precisamente ShotGunSniper e così via.

ShotGun implements Gun{
    public void shoot(){
       \\shotgun implementation of shoot.
    } 
}

Sniper implements Gun{
    public void shoot(){
       \\sniper implementation of shoot.
    } 
}

Classe di tiratori

Il tiratore ha tutte le armi nella sua armatura. Consente di creare un List per rappresentarlo.

List<Gun> listOfGuns = new ArrayList<Gun>();

Il tiratore scorre ciclicamente le sue pistole, come e quando necessario, usando la funzione switchGun()

public void switchGun(){
    //code to cycle through the guns from the list of guns.
    currentGun = //the next gun in the list.
}

Possiamo impostare la pistola corrente, usando la funzione sopra e semplicemente chiamare la funzione shoot(), quando viene chiamato fire().

public void fire(){
    currentGun.shoot();
}

Il comportamento della funzione di scatto varierà in base alle diverse implementazioni dell'interfaccia Gun.

Conclusione

Creare un'interfaccia, quando una funzione di classe dipende da na funzione di un'altra classe, che è soggetta a modificarne il comportamento, in base all'istanza (oggetto) della classe implementata.

per es. La funzione fire() della classe Shooter prevede che le pistole (Sniper, ShotGun) implementino la funzione shoot(). Quindi se accendiamo la pistola e il fuoco.

shooter.switchGun();
shooter.fire();

Abbiamo modificato il comportamento della funzione fire().

2
Sorter

Le interfacce vengono generalmente utilizzate quando si desidera definire un comportamento che gli oggetti possono mostrare.

Un buon esempio di ciò nel mondo .NET è l'interfaccia IDisposable , che viene utilizzata su tutte le classi Microsoft che utilizzano risorse di sistema che devono essere rilasciate manualmente. Richiede che la classe che lo implementa abbia un metodo Dispose ().

(Il metodo Dispose () viene anche chiamato dal costrutto del linguaggio using per VB.NET e C # , che funziona solo su IDisposables)

Tieni presente che puoi verificare se un oggetto implementa un'interfaccia specifica utilizzando costrutti come TypeOf ... Is (VB.NET), is (C #), instanceof (Java), ecc ...

1
Powerlord

Poiché probabilmente molte persone hanno già risposto, è possibile utilizzare le interfacce per applicare determinati comportamenti tra le classi che non implementeranno tali comportamenti allo stesso modo. Quindi implementando un'interfaccia stai dicendo che la tua classe ha il comportamento dell'interfaccia. L'interfaccia IAnimal non sarebbe un'interfaccia tipica perché le classi Dog, Cat, Bird, ecc. Sono tipi di animali e dovrebbero probabilmente estenderla, il che è un caso di eredità. Al contrario, un'interfaccia sarebbe più simile al comportamento animale in questo caso, come IRunnable, IFlyable, ITrainable, ecc.

Le interfacce sono buone per molte cose, una delle cose chiave è la connettività. Ad esempio, la dichiarazione di un metodo con un parametro List consentirà il passaggio di tutto ciò che implementa l'interfaccia List, consentendo allo sviluppatore di rimuovere e collegare un altro elenco in un secondo momento senza dover riscrivere una tonnellata di codice.

È possibile che non utilizzerai mai le interfacce, ma se stai progettando un progetto da zero, in particolare un framework di qualche tipo, probabilmente vorrai conoscerli.

Consiglio di leggere il capitolo sulle interfacce in Java Design di Coad, Mayfield e Kern. Lo spiegano un po 'meglio del testo introduttivo medio. Se non usi Java, puoi semplicemente leggere l'inizio del capitolo, che è principalmente concetti.

1
Ryan Thames

Espandere ciò che ha detto Larsenal. Un'interfaccia è un contratto che devono seguire tutte le classi di attuazione. Per questo motivo, è possibile utilizzare una tecnica chiamata programmazione al contratto. Ciò consente al software di diventare indipendente dall'implementazione.

1
Matthew Brubaker

Come qualsiasi tecnica di programmazione che aggiunge flessibilità al tuo sistema, anche le interfacce aggiungono un certo livello di complessità. Spesso sono fantastici e puoi usarlo ovunque (puoi creare un'interfaccia per tutte le tue classi) - ma così facendo, creeresti un sistema più complesso che sarebbe più difficile da mantenere.

C'è un compromesso qui, come al solito: flessibilità rispetto alla manutenibilità. Qual è più importante? Non ci sono risposte - dipende dal progetto. Ma ricorda che tutti i software dovranno essere mantenuti ...

Quindi il mio consiglio: non usare le interfacce fino a quando non ne hai davvero bisogno. (Con Visual Studio, puoi estrarre un'interfaccia da una classe esistente in 2 secondi, quindi non avere fretta.)

Detto questo, quando è necessario creare un'interfaccia?

Lo faccio quando sto eseguendo il refactoring di un metodo che improvvisamente deve elaborare due o più classi simili. Quindi creo un'interfaccia, assegno questa interfaccia a due (o più) classi simili e cambio il tipo di parametro del metodo (sostituisco il tipo di classe con il tipo di interfaccia).

E funziona: o)

Un'eccezione: quando io quando derido oggetti, l'interfaccia è molto più facile da usare. Quindi spesso creo un'interfaccia solo per questo.

PS: quando scrivo "interfaccia", intendo: "interfaccia di qualsiasi classe base", comprese le classi di interfaccia pure. Nota che le classi astratte sono spesso una scommessa migliore delle interfacce pure poiché puoi aggiungere logica ad esse.

Saluti, Sylvain.

1
Sylvain Rodrigue

Le interfacce diventeranno evidenti quando diventerai un sviluppatore di librerie (qualcuno che codifica per altri programmatori). Molti di noi iniziano come sviluppatori di applicazioni, dove utilizziamo API e librerie di programmazione esistenti.

Sulla stessa linea che le interfacce sono un contratto , nessuno ha ancora menzionato che le interfacce sono un ottimo modo per rendere stabili alcune parti del codice . Ciò è particolarmente utile quando si tratta di un progetto team (o quando si sviluppa codice utilizzato da altri sviluppatori). Quindi, ecco uno scenario concreto per te:

Quando stai sviluppando il codice in un team, altri probabilmente useranno il codice che scrivi. Saranno molto felici quando codificheranno per le tue interfacce (stabili) e sarai felice quando avrai la libertà di cambiare le tue implementazioni (nascoste dietro l'interfaccia) senza rompere il codice del tuo team. È una variante di nascondere le informazioni (le interfacce sono pubbliche, le implementazioni sono nascoste ai programmatori client). Maggiori informazioni su varianti protette .

Vedi anche questo domanda correlata sulla codifica di un'interfaccia .

1
Fuhrmanator

Ci sono tanti scopi per usare un'interfaccia.

  1. Utilizzare nel comportamento polimorfico. Dove si desidera chiamare metodi specifici di una classe figlio con un'interfaccia con un riferimento alla classe figlio.

  2. Avere un contratto con le classi per implementare tutti i metodi dove è necessario, come l'uso più comune è con gli oggetti COM, dove una classe wrapper viene generata su un DLL che eredita l'interfaccia; questi metodi sono chiamati dietro le quinte e devi solo implementarli ma con la stessa struttura definita in COM DLL che puoi conoscere solo attraverso l'interfaccia che essi espongono.

  3. Ridurre l'utilizzo della memoria caricando metodi specifici in una classe. Come se avessi tre oggetti business e fossero implementati in una singola classe, puoi usare tre interfacce.

Ad esempio IUser, IOrder, IOrderItem

public interface IUser()
{

void AddUser(string name ,string fname);

}

// Same for IOrder and IOrderItem
//


public class  BusinessLayer: IUser, IOrder, IOrderItem

{    
    public void AddUser(string name ,string fname)
    {
        // Do stuffs here.
    }

    // All methods from all interfaces must be implemented.

}

Se vuoi solo aggiungere un utente, fai così:

IUser user = new (IUser)BusinessLayer();

// It will load  all methods into memory which are declared in the IUser interface.

user.AddUser();
1
sajid khan