it-swarm.it

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

"Classe astratta" e "interfaccia" sono concetti simili, con l'interfaccia che è la più astratta delle due. Un fattore di differenziazione è che le classi astratte forniscono implementazioni di metodi 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 (cioè, non c'è ereditarietà multipla), ma può implementare più interfacce. Ciò rende le interfacce meno restrittive e più flessibili. Quindi, in C #, quando dovremmo usare le classi astratte anziché le interfacce con i metodi di estensione?

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

70
Gulshan

Quando è necessaria l'implementazione di una parte della classe. Il miglior esempio che ho usato è il modello metodo del 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 i dettagli di come verranno implementati. Le classi di derivazione devono implementare i metodi astratti, ma non il metodo Do ().

I metodi di estensione non soddisfano necessariamente la parte "deve essere una parte della classe" dell'equazione. Inoltre, iirc, i metodi di estensione non possono (sembrano) essere di portata pubblica.

modifica

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

Personalmente, ho difficoltà a vedere il beneficio di alterare una pratica attualmente comune, ma vedo anche pochi o nessun aspetto negativo nel farlo.

Va notato che è possibile programmare in questo modo in molte lingue tramite le classi Utility. Le estensioni forniscono solo lo zucchero sintattico per far sembrare che i metodi appartengano alla classe.

63
Steven Evers

Si tratta di che cosa vuoi modellare:

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

Ad esempio, un cane è un animale, quindi abbiamo

class Dog : Animal { ... }

Dato che non ha senso creare effettivamente un generico all-animal (come sarebbe?), Facciamo questo Animal base class abstract - ma è ancora una classe base. E la classe Dog non ha senso senza essere una Animal.

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

Prendi ad es. IComparable - un oggetto che supporta il confronto con un altro .

La funzionalità di una classe non dipende dalle interfacce che implementa, l'interfaccia fornisce solo un modo generico per accedere alla funzionalità. Potremmo ancora Dispose di Graphics o FileStream senza che abbiano implementato IDisposable. L'interfaccia collega semplicemente i metodi insieme.

In linea di principio, si potrebbero aggiungere e rimuovere interfacce proprio come le estensioni senza modificare il comportamento di una classe, arricchendo semplicemente l'accesso ad essa. Non puoi però togliere una classe di base poiché l'oggetto diventerebbe insignificante!

25
Dario

Ho appena realizzato che non uso classi astratte (almeno non create) da anni.

La classe astratta è una strana bestia tra interfaccia e implementazione. C'è qualcosa nelle classi astratte che pizzica il mio senso del ragno. Direi che non si dovrebbe "esporre" l'implementazione dietro l'interfaccia in alcun modo (o fare alcun collegamento).

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

Vorrei andare alle interfacce.

3
Maglob

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

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

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

Cominciamo dall'inizio.

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

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

Per poter applicare la raccomandazione GoF Book: "Per programmare per l'interfaccia e non per l'implementazione", C++ ha supportato le classi astratte e l'ereditarietà dell'implementazione multipla per essere 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à, ereditarietà di interfaccia, per offrire almeno due modi diversi di supportare "Programmare per l'interfaccia e non per l'implementazione", con un avvertimento importante: solo C # supporta l'ereditarietà multipla con l'ereditarietà dell'interfaccia (e non con l'ereditarietà dell'implementazione).

Quindi, i motivi architettonici alla base delle interfacce in C # sono la raccomandazione GoF.

Spero che questo possa essere d'aiuto.

Cordiali saluti, Gastón

L'applicazione di metodi di estensione a un'interfaccia è utile per applicare comportamenti comuni tra classi che possono condividere solo un'interfaccia comune. Tali classi possono già esistere ed essere chiuse alle estensioni con altri mezzi.

Per i nuovi progetti preferirei l'uso di 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 devo incapsulare l'implementazione privata dietro un'interfaccia pubblica, una classe astratta sarebbe l'unico modo.

1
Ed James

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

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

0
Beginner