Quando utilizzare le classi astratte anziché le interfacce con i metodi di estensione in C #?

69

"Classe astratta" e "interfaccia" sono concetti simili, con l'interfaccia che è il più astratto dei due. Un fattore di differenziazione è che le classi astratte forniscono implementazioni del metodo per le classi derivate quando necessario. In C #, tuttavia, questo fattore di differenziazione è stato ridotto dalla recente introduzione di metodi di estensione, che consentono di fornire implementazioni per i metodi di interfaccia. Un altro fattore di differenziazione è che una classe può ereditare solo una classe astratta (vale a dire, non esiste un'eredità multipla), ma può implementare più interfacce. Ciò rende le interfacce meno restrittive e più flessibili. Quindi, in C #, quando dovremmo utilizzare le classi astratte anziché le interfacce con i metodi di estensione?

Un esempio notevole del modello di metodo dell'interfaccia + estensione è LINQ, in cui viene fornita la funzionalità di query per qualsiasi tipo che implementa IEnumerable tramite una moltitudine di metodi di estensione.

    
posta Gulshan 31.01.2011 - 10:17
fonte

7 risposte

61

Quando hai bisogno di una parte della classe da implementare. Il miglior esempio che ho usato è il metodo del modello modello.

public abstract class SomethingDoer
{
    public void Do()
    {
        this.DoThis();
        this.DoThat();
    }

    protected abstract void DoThis();
    protected abstract void DoThat();
}

Pertanto, è possibile definire i passaggi che verranno eseguiti quando viene chiamato Do (), senza conoscere le specifiche di come verranno implementati. Le classi derivate devono implementare i metodi astratti, ma non il metodo Do ().

I metodi di estensioni non soddisfano necessariamente la parte "deve essere una parte della classe" dell'equazione. Inoltre, iirc, i metodi di estensione non possono (sembrano) essere qualcosa di diverso da quello pubblico.

modifica

La domanda è più interessante di quanto avessi inizialmente dato credito. Dopo un ulteriore esame, Jon Skeet ha risposto a una domanda come questa su SO a favore di usando le interfacce + metodi di estensione. Inoltre, un potenziale svantaggio sta utilizzando la riflessione su una gerarchia di oggetti progettata in questo modo .

Personalmente, sto riscontrando dei problemi nel vedere il vantaggio di alterare una pratica attualmente comune, ma vedo anche pochi svantaggi nel farlo.

Va notato che è possibile programmare questo modo in molte lingue tramite le classi di utilità. Le estensioni forniscono solo lo zucchero sintattico per far apparire i metodi come appartenenti alla classe.

    
risposta data 31.01.2011 - 11:15
fonte
24

Riguarda che vuoi modellare:

Le classi astratte funzionano con ereditarietà . Essendo solo classi base speciali, modellano alcune relazioni is-a .

Ad esempio, un cane è un animale, quindi abbiamo

class Dog : Animal { ... }

Come non ha senso effettivamente creare un generico all-animale (come sarebbe?), rendiamo questo Animal base class abstract - ma è ancora un classe base. E la classe Dog non ha senso senza essere Animal .

Interfacce d'altra parte sono una storia diversa. Non usano l'ereditarietà ma forniscono il polimorfismo (che può essere implementato anche con l'ereditarietà). Non modellano una relazione is-a , ma più di un che supporta .

Prendi per es. IComparable - un oggetto che supporta essere comparato con un altro .

La funzionalità di una classe non dipende dalle interfacce implementate, l'interfaccia fornisce solo un modo generico di accedere alla funzionalità. Potremmo ancora Dispose di Graphics o FileStream senza averli implementati IDisposable . L'interfaccia riguarda solo i metodi insieme.

In linea di principio, si potrebbero aggiungere e rimuovere interfacce come le estensioni senza modificare il comportamento di una classe, semplicemente arricchendo l'accesso ad essa. Non puoi però portare via una classe base in quanto l'oggetto diventerebbe privo di significato!

    
risposta data 31.01.2011 - 13:13
fonte
3

Mi sono appena reso conto che non ho usato classi astratte (almeno non create) da anni.

La classe astratta è una bestia un po 'strana tra interfaccia e implementazione. C'è qualcosa nelle classi astratte che freme il mio senso di ragno. Direi che non si dovrebbe "esporre" l'implementazione dietro l'interfaccia in alcun modo (o creare legami).

Anche se è necessario un comportamento comune tra le classi che implementano un'interfaccia, utilizzerei una classe helper indipendente, piuttosto che una classe astratta.

Vorrei andare per le interfacce.

    
risposta data 31.01.2011 - 11:06
fonte
2

IMHO, penso che ci sia un mix di concetti qui.

Le classi usano un certo tipo di ereditarietà, mentre le interfacce usano un diverso tipo di ereditarietà.

Entrambi i tipi di eredità sono importanti e utili, e ognuno ha i suoi pro e contro.

Iniziamo dall'inizio.

La storia con le interfacce inizia da molto tempo con il C ++. A metà degli anni '80, quando il C ++ fu sviluppato, l'idea di interfacce come un tipo diverso di tipo non era ancora stata realizzata (sarebbe arrivata in tempo).

C ++ aveva solo un tipo di ereditarietà, il tipo di ereditarietà usato dalle classi, chiamato ereditarietà dell'implementazione.

Per poter applicare il consiglio di GoF Book: "Per programmare l'interfaccia, e non per l'implementazione", le classi astratte supportate da C ++ e l'ereditarietà multipla dell'implementazione sono in grado di fare ciò che le interfacce in C # sono in grado (e utili! ) di fare.

C # introduce un nuovo tipo di tipo, interfacce e un nuovo tipo di ereditarietà, l'ereditarietà dell'interfaccia, per offrire almeno due modi diversi di supportare "Programmare per l'interfaccia, e non per l'implementazione", con un avvertimento importante : C # supporta solo l'ereditarietà multipla con l'ereditarietà dell'interfaccia (e non con l'ereditarietà dell'implementazione).

Quindi, le ragioni architettoniche dietro le interfacce in C # sono le raccomandazioni del GoF.

Spero che questo possa essere di aiuto.

Cordiali saluti, Gastón

    
risposta data 03.09.2012 - 17:42
fonte
1

L'applicazione di metodi di estensione a un'interfaccia è utile per applicare un comportamento comune tra classi che possono condividere solo un'interfaccia comune. Tali classi potrebbero già esistere e essere chiuse alle estensioni tramite altri mezzi.

Per i nuovi design, preferirei utilizzare i metodi di estensione sulle interfacce. Per una gerarchia di tipi, i metodi di estensione forniscono un mezzo per estendere il comportamento senza dover aprire l'intera gerarchia per la modifica.

Tuttavia, i metodi di estensione non sono in grado di accedere all'implementazione privata, quindi nella parte superiore di una gerarchia, se ho bisogno di incapsulare un'implementazione privata dietro un'interfaccia pubblica, una classe astratta sarebbe l'unico modo.

    
risposta data 31.01.2011 - 12:24
fonte
0

Penso che in C # l'ereditarietà multipla non sia supportata ed è per questo che il concetto di interfaccia è introdotto in C #.

In caso di classi astratte, l'ereditarietà multipla non è supportata neanche. Quindi è facile decidere se utilizzare le classi o le interfacce astratte.

    
risposta data 20.12.2012 - 10:49
fonte
-1

Sono in procinto di implementare una classe Abstract nel mio progetto semplicemente perché C # non supporta gli operatori (conversioni implicite, nel mio caso) su Interfacce.

    
risposta data 30.05.2012 - 22:48
fonte

Leggi altre domande sui tag