È una cattiva abitudine non usare le interfacce? [chiuso]

39

Uso raramente le interfacce e le trovo comuni in altri codici.

Inoltre creo raramente classi secondarie e super (mentre creo le mie classi) nel mio codice.

  • È una brutta cosa?
  • Suggeriresti di cambiare questo stile?
  • Questo stile ha effetti collaterali?
  • È perché non ho lavorato su progetti di grandi dimensioni?
posta jineesh joseph 19.06.2011 - 18:47
fonte

11 risposte

35

Ci sono diversi motivi per cui potresti voler utilizzare le interfacce:

  1. Le interfacce sono adatte a situazioni in cui il tuo le applicazioni richiedono molte possibilmente tipi di oggetti non correlati da fornire alcune funzionalità.
  2. Le interfacce sono più flessibili di classi di base perché è possibile definire una singola implementazione che può implementare più interfacce.
  3. Le interfacce sono migliori in situazioni in cui non è necessario ereditare implementazione da una classe base.
  4. Le interfacce sono utili nei casi in cui non puoi usare l'ereditarietà della classe. Ad esempio, le strutture non possono ereditare dalle classi, ma possono farlo implementare interfacce.

link

Le interfacce sono come qualsiasi altra cosa nella programmazione. Se non ne hai bisogno, non usarli. Li ho visti ampiamente usati come una questione di stile, ma se non hai bisogno delle proprietà e delle capacità speciali fornite da un'interfaccia, non vedo il vantaggio di usarli "solo perché".

    
risposta data 19.06.2011 - 18:55
fonte
17

Sia l'ereditarietà delle classi che le interfacce hanno entrambi il loro posto. L'ereditarietà significa "è un" mentre un'interfaccia fornisce un contratto che definisce ciò che "si comporta come".

Direi che usare le interfacce più spesso non è affatto una cattiva pratica. Attualmente sto leggendo "Effective C # - 50 Ways specifici per migliorare il tuo C #" di Bill Wagner. L'articolo numero 22 afferma, e io cito, "Preferisci la definizione e l'implementazione delle interfacce all'ereditarietà".

Generalmente utilizzo le classi base quando devo definire un'implementazione specifica del comportamento comune tra i tipi concettualmente correlati. Più spesso uso interfacce. In effetti, di solito inizio definendo un'interfaccia per una classe quando inizio a crearne una ... anche se alla fine non compilo l'interfaccia, trovo che sia d'aiuto definire l'API pubblica della classe dal get go. Se trovo che ho più classi che implementano l'interfaccia e la logica di implementazione è identica, solo allora mi chiederò se avrebbe senso implementare una classe base comune tra i tipi.

Un paio di citazioni dal libro di Bill Wagners ...

"Le classi base astratte possono fornire alcune implementazioni per i tipi derivati, oltre a descrivere il comportamento comune.È possibile specificare membri dei dati, metodi concreti, implementazione per metodi virtuali, proprietà, eventi e indicizzatori. per alcuni dei metodi, fornendo in tal modo un riutilizzo di implementazione comune.Tutti gli elementi possono essere virtuali, astratti o non virtuali.Una classe base astratta può fornire un'implementazione per qualsiasi comportamento concreto, le interfacce non possono.Un riutilizzo dell'implementazione offre un altro vantaggio: aggiungere un metodo alla classe base, tutte le classi derivate vengono automaticamente e implicitamente migliorate, in questo senso le classi base forniscono un modo per estendere il comportamento di diversi tipi in modo efficiente nel tempo: aggiungendo e implementando funzionalità nella classe base, tutte le classi derivate incorporare immediatamente questo comportamento: l'aggiunta di un membro all'interfaccia interrompe tutte le classi che implementano tale interfaccia mantenere il nuovo metodo e non verrà più compilato. Ogni implementatore deve aggiornare quel tipo per includere il nuovo membro. Scegliere tra una classe base astratta e un'interfaccia è una questione su come meglio supportare le tue astrazioni nel tempo. Le interfacce sono corrette: rilasci un'interfaccia come contratto per un insieme di funzionalità che qualsiasi tipo può implementare. Le classi base possono essere estese nel tempo. Quelle estensioni diventano parte di ogni classe derivata. I due modelli possono essere mescolati per riutilizzare il codice di implementazione mentre supportano più interfacce. "

"Le interfacce di codifica offrono maggiore flessibilità agli altri sviluppatori rispetto alla codifica per tipi di classi base."

"L'utilizzo delle interfacce per definire le API per una classe offre una maggiore flessibilità."

"Quando il tuo tipo espone le proprietà come tipi di classe, espone l'intera interfaccia a quella classe.Usando le interfacce, puoi scegliere di esporre solo i metodi e le proprietà che i client devono utilizzare."

"Le classi base descrivono e implementano comportamenti comuni attraverso tipi concreti correlati: le interfacce descrivono parti atomiche di funzionalità che possono essere implementate da tipi concreti non collegati, entrambe hanno il loro posto e le classi definiscono i tipi creati. Se capisci le differenze, creerai più progetti espressivi che sono più resilienti di fronte alle modifiche.Usilizzi le gerarchie di classi per definire i tipi correlati.Scopri la funzionalità utilizzando le interfacce implementate in questi tipi. "

    
risposta data 19.06.2011 - 19:36
fonte
8

Una cosa che non è stata menzionata è il test: in tutte le librerie di mocking C #, così come in alcune per Java, le classi non possono essere derise a meno che non implementino un'interfaccia. Questo porta molti progetti che seguono Agile / Pratiche TDD per fornire alla classe ogni la propria interfaccia.

Alcune persone considerano questa best practice, perché "riduce l'accoppiamento", ma non sono d'accordo - penso che sia solo una soluzione a una carenza nella lingua.

Penso che le interfacce siano utilizzate al meglio quando hai due o più classi che, astrattamente, fanno la "stessa cosa", ma in modi diversi.

Ad esempio, il framework .Net ha più classi che memorizzano elenchi di stuff , ma tutti memorizzano le cose in modi diversi. Pertanto, ha senso avere un'interfaccia IList<T> astratta, che può essere implementata utilizzando metodi diversi.

Dovresti usarlo anche quando vuoi che 2+ classi siano intercambiabili o sostituibili in futuro. Se in futuro uscirà un nuovo modo di archiviare gli elenchi, AwesomeList<T> , assumendo che tu abbia usato IList<T> per tutto il tuo codice, cambiarlo per usare AwesomeList<T> significherebbe solo cambiare alcune dozzine di righe, piuttosto che poche centinaia / mille.

    
risposta data 20.06.2011 - 01:23
fonte
5

Il risultato principale di non utilizzare l'ereditarietà e le interfacce quando sono appropriate è accoppiamento stretto . Questo può essere un po 'difficile da imparare a riconoscere, ma di solito il sintomo più ovvio è quando apporti una modifica, ti accorgi di dover passare spesso attraverso un sacco di altri file per apportare modifiche a un effetto a catena.

    
risposta data 19.06.2011 - 20:33
fonte
4

No, non è affatto male. Dovrebbero essere utilizzate interfacce esplicite, se e solo se, due classi con un'interfaccia comune devono essere intercambiabili in fase di esecuzione. Se non hanno bisogno di essere intercambiabili, allora non li hanno ereditati. E 'così semplice. L'ereditarietà è fragile e dovrebbe essere evitata laddove possibile. Se puoi evitarlo o usare generici, allora fallo

Il problema è che, in linguaggi come C # e Java con generici deboli in fase di compilazione, si può finire per violare DRY perché non c'è modo di scrivere un metodo che possa gestire più di una classe a meno che tutte le classi ereditino dalla stessa base . C # 4 dynamic può affrontare questo, però.

Il fatto è che l'ereditarietà è come le variabili globali- una volta che lo aggiungi e il tuo codice dipende da esso, Dio ti aiuta a portarlo via. Tuttavia, puoi aggiungerlo in qualsiasi momento e puoi persino aggiungerlo senza alterare la classe base usando un wrapper di sorta.

    
risposta data 19.06.2011 - 20:32
fonte
3

Sì, non (o troppo raramente) usare le interfacce è probabilmente una brutta cosa. Le interfacce (in senso astratto e il costrutto del linguaggio C # / Java è un'approssimazione abbastanza buona di quel senso astratto) definiscono i punti di interazione espliciti tra sistemi e sottosistemi. Ciò aiuta a ridurre l'accoppiamento e rende il sistema più manutenibile. Come per tutto ciò che migliora la manutenibilità, diventa tanto più importante quanto più grande è un sistema.

    
risposta data 19.06.2011 - 23:54
fonte
3

Non ho usato un'interfaccia da anni. Certo, questo è perché ormai da anni programmavo quasi esclusivamente in Erlang e l'intero concetto di un'interfaccia semplicemente non esiste. (Il più vicino che ottieni è un "comportamento" e non è proprio la stessa cosa a meno che non ti strizzi davvero strong e guardandoli con la coda dell'occhio.)

Quindi, in realtà, la tua domanda è dipendente dal paradigma (OOP in questo caso) e, inoltre, è davvero abbastanza dipendente dalla lingua (esistono linguaggi OOP senza interfacce).

    
risposta data 20.06.2011 - 01:13
fonte
2

Se stai parlando di usare Java, un motivo per usare le interfacce è che abilitano l'uso di oggetti proxy senza librerie di generazione del codice. Questo può essere un vantaggio sostanziale quando si lavora con un quadro complesso come Spring. Inoltre, alcune funzionalità richiedono le interfacce : RMI è il classico esempio di questo, poiché devi descrivere la funzionalità che fornisci in termini di interfacce (che ereditano da java.rmi.Remote ), tuttavia, si procede all'implementazione loro.

    
risposta data 19.06.2011 - 22:29
fonte
1

Le cose stanno cambiando ( MS Moles ), ma la ragione principale per cui penso sia buona codificare quasi esclusivamente le interfacce è che sono facili da prendere in giro e adattarsi naturalmente a un'architettura IoC.

IMO dovresti lavorare sempre con le interfacce, o completamente stupidi DAO ovunque sia possibile. Una volta che entri in questa mentalità, e inizi a utilizzare una libreria che non si espone attraverso le interfacce e fa tutto tramite oggetti concreti che devo essere onesto, sembra tutto un po 'goffo.

    
risposta data 19.06.2011 - 20:44
fonte
0

Per i vecchi progetti di moda, uno usa le interfacce per evitare riferimenti circolari, perché i riferimenti circolari potrebbero diventare enormi problemi di manutenzione a lungo termine.

Bad:

class B; // forward declaration
class A
{
  B* b;
};

class B
{
  A* a;
}

Non male:

class PartOfClassB_AccessedByA
{
};

class A
{
  PartOfClassB_AccessedByA* b;
};

class B : public PartOfClassB_AccessedByA
{
  A* a;
}

Solitamente A, B, PartOfClassB_AccessedByA implementato con file separati.

    
risposta data 20.06.2011 - 13:32
fonte
0

La programmazione basata sull'interfaccia aiuta a rendere il codice più flessibile e più facile da testare. Le classi di implementazione possono essere modificate senza toccare il codice cliente [Flessibilità]. Mentre testare il codice uno può sostituire la programmazione basata su oInterface aiuta a rendere il codice più flessibile e più facile da testare. Le classi di implementazione possono essere modificate senza toccare il codice cliente [Flessibilità]. Durante il test del codice uno può sostituire l'oggetto reale con oggetti finti [Testabilità] .bject con oggetti mock [Testabilità].

    
risposta data 20.06.2011 - 16:18
fonte

Leggi altre domande sui tag