Quando utilizzare un'interfaccia anziché una classe astratta e viceversa?


427

Questa potrebbe essere una domanda OOP generica. Volevo fare un confronto generico tra un'interfaccia e una classe astratta sulla base del loro utilizzo.

Quando si vorrebbe usare un'interfaccia e quando si vorrebbe usare una classe astratta ?



1
Oltre alle risposte di seguito, questo è un breve elenco di dove potresti voler preferire le interfacce e dove potresti non: Quando usare le interfacce: msdn.microsoft.com/en-us/library/3b5b8ezk(v=vs.80) .aspx
Anthony,

usa l'abstract quando non sei sicuro di cosa farà la lezione. usa l'interfaccia se lo sei.
Uğur Gümüşhan,

Sono interessato a vedere quanti sviluppatori, che non lavorano in Microsoft, definiscono e utilizzano le interfacce nel loro sviluppo quotidiano.
user1451111

Risposte:


432

Ho scritto un articolo a riguardo:

Classi astratte e interfacce

riassumendo:

Quando parliamo di classi astratte stiamo definendo le caratteristiche di un tipo di oggetto; specificando cos'è un oggetto .

Quando parliamo di un'interfaccia e definiamo le capacità che promettiamo di fornire, stiamo parlando di stabilire un contratto su ciò che l'oggetto può fare.


114
Questo è stato ery utile: Interfaces do not express something like "a Doberman is a type of dog and every dog can walk" but more like "this thing can walk". Grazie
escluso il

2
Sembra che il tuo link sia morto.
Kim Ahlstrøm Meyn Mathiassen,

La spiegazione di Alex qui sotto, ri: la differenza tra solo la descrizione delle funzioni implementate rispetto alla descrizione dello stato memorizzato, sembra una risposta migliore a questa domanda, perché le differenze non sono solo filosofiche.
Duncan Malashock,

1
Duncan Malashock, non proprio. La risposta di Jorge è la migliore. La risposta di Alex si concentra sulla meccanica, mentre Jorge è più sulla semantica.
Nazar Merza,

8
Mi piace la dichiarazione prima della risposta specificata:Use abstract classes and inheritance if you can make the statement “A is a B”. Use interfaces if you can make the statement “A is capable of [doing] as”
S1r-Lanzelot,

433

Una classe astratta può avere stato o funzionalità condivisi. Un'interfaccia è solo una promessa per fornire lo stato o la funzionalità. Una buona classe astratta ridurrà la quantità di codice che deve essere riscritto perché la sua funzionalità o stato può essere condivisa. L'interfaccia non ha informazioni definite da condividere


65
Questa, per me, è la migliore risposta qui ed è un peccato non essere stata votata più in alto. Sì, ci sono differenze filosofiche tra i due concetti, ma il punto fondamentale è che le classi astratte assicurano che tutti i discendenti condividano funzionalità / stato, in cui un'interfaccia garantisce solo un legame comune.
drharris,

3
Ad esempio, una classe base astratta viene utilizzata per il modello di progettazione del metodo modello, mentre un'interfaccia viene utilizzata per il modello di progettazione strategia .
Raedwald,

1
Penso che il riassunto di Jorge spieghi l'esistenza primaria ma alla base di entrambi, mentre la risposta di Alex è la differenza nei risultati. Vorrei poter contrassegnare entrambi come risposte giuste, ma preferisco comunque la risposta di Jorge.
Chirantan,

E Qui è esempio con il codice.
Shaijut,

Per me, questo "Una buona classe astratta ridurrà la quantità di codice che deve essere riscritto perché la sua funzionalità o stato può essere condivisa". l'affermazione è il nocciolo della risposta.
Div Tiwari,

82

Personalmente, non ho quasi mai bisogno di scrivere lezioni astratte.

Molte volte vedo che le classi astratte vengono (mis) utilizzate, è perché l'autore della classe astratta sta usando il modello "Metodo modello".

Il problema con "Metodo modello" è che è quasi sempre rientrato in qualche modo - la classe "derivata" conosce non solo il metodo "astratto" della sua classe base che sta implementando, ma anche i metodi pubblici della classe base , anche se la maggior parte delle volte non è necessario chiamarli.

Esempio (eccessivamente semplificato):

abstract class QuickSorter
{
    public void Sort(object[] items)
    {
        // implementation code that somewhere along the way calls:
        bool less = compare(x,y);
        // ... more implementation code
    }
    abstract bool compare(object lhs, object rhs);
}

Quindi qui, l'autore di questa classe ha scritto un algoritmo generico e intende che le persone lo usino "specializzandolo" fornendo i propri "hook" - in questo caso, un metodo di "confronto".

Quindi l'uso previsto è qualcosa del genere:

class NameSorter : QuickSorter
{
    public bool compare(object lhs, object rhs)
    {
        // etc.
    }
}

Il problema è che hai accoppiato indebitamente due concetti:

  1. Un modo di confrontare due elementi (quale oggetto dovrebbe essere il primo)
  2. Un metodo di ordinamento degli articoli (es. Quicksort vs merge sort ecc.)

Nel codice di cui sopra, in teoria, l'autore del metodo "confrontare" può rientrante richiamare nella superclasse "Sort" metodo ... anche se in pratica non potranno mai avere bisogno di fare questo.

Il prezzo da pagare per questo accoppiamento non necessario è che è difficile cambiare la superclasse e, nella maggior parte delle lingue OO, impossibile cambiarla in fase di esecuzione.

Il metodo alternativo è invece utilizzare il modello di progettazione "Strategia":

interface IComparator
{
    bool compare(object lhs, object rhs);
}

class QuickSorter
{
    private readonly IComparator comparator;
    public QuickSorter(IComparator comparator)
    {
        this.comparator = comparator;
    }

    public void Sort(object[] items)
    {
        // usual code but call comparator.Compare();
    }
}

class NameComparator : IComparator
{
    bool compare(object lhs, object rhs)
    {
        // same code as before;
    }
}

Quindi nota ora: tutto ciò che abbiamo sono interfacce e implementazioni concrete di quelle interfacce. In pratica, non hai davvero bisogno di nient'altro per realizzare un progetto OO di alto livello.

Per "nascondere" il fatto che abbiamo implementato "l'ordinamento dei nomi" utilizzando una classe "QuickSort" e un "NameComparator", potremmo comunque scrivere un metodo di fabbrica da qualche parte:

ISorter CreateNameSorter()
{
    return new QuickSorter(new NameComparator());
}

Ogni volta che hai una classe astratta puoi farlo ... anche quando c'è una relazione di rientro naturale tra la base e la classe derivata, di solito paga renderli espliciti.

Un ultimo pensiero: tutto ciò che abbiamo fatto sopra è "comporre" una funzione "NameSorting" utilizzando una funzione "QuickSort" e una funzione "NameComparison" ... in un linguaggio di programmazione funzionale, questo stile di programmazione diventa ancora più naturale, con meno codice.


5
Solo perché puoi usare le classi astratte o il modello Metodo modello non significa che devi evitarle. Il modello di strategia è un modello diverso per una situazione diversa come in questo esempio, ma ci sono molti esempi in cui un modello di modello è molto più adatto della strategia.
Jorge Córdoba,

5
Bene, nella mia esperienza non li ho mai incontrati (situazioni in cui è preferibile il metodo template) ... o raramente comunque. E questo è tutto "astratto": il supporto del linguaggio per il modello di progettazione del "metodo modello".
Paul Hollingsworth,

Ok, l'ho usato una volta per un sistema esperto in cui il processo era qualcosa di simile, prendi 1. FillTheParameters, 2. Crea il prodotto vettoriale tra di loro, 3. Per ogni risultato di calcolo delle coppie, 4. Unisci i risultati, dove i passaggi 1 e 3 dove delegato e 2 e 4 implementati nella classe base.
Jorge Córdoba,

10
Trovo che quasi ogni uso di classi astratte sia più difficile da capire. Pensare in termini di scatole che comunicano tra di loro invece di relazioni ereditarie è più facile (per me) ... Ma sono anche d'accordo sul fatto che le lingue OO attuali costringono troppo alla piastra ... Funzionale sarà il modo di andare oltre OO
Paul Hollingsworth

4
L'esempio di uso improprio è piuttosto banale. Raramente si riduce a una funzionalità così bella come il confronto. Molto più comuni sono le situazioni in cui vi sono alcune funzionalità predefinite che le classi derivate sostituiscono o estendono (e in quest'ultimo caso è perfettamente valido chiamare la funzione della classe base). Nel tuo esempio non esiste una funzionalità predefinita, quindi l'utilizzo della classe astratta non ha giustificazione.
SomeWittyUsername

41

Se stai guardando Java come linguaggio OOP,

"L' interfaccia non fornisce l'implementazione del metodo " non è più valida con l'avvio di Java 8. Ora Java fornisce l'implementazione nell'interfaccia per i metodi predefiniti.

In termini semplici, vorrei usare

interfaccia: per implementare un contratto da più oggetti non correlati. Fornisce funzionalità " HAS A ".

classe astratta: per implementare lo stesso o diverso comportamento tra più oggetti correlati. Stabilisce una relazione" IS A ".

Il sito Web Oracle offre differenze chiave tra interfacee abstractclasse.

Prendi in considerazione l'uso di classi astratte se:

  1. Vuoi condividere il codice tra diverse classi strettamente correlate.
  2. Ti aspetti che le classi che estendono la tua classe astratta abbiano molti metodi o campi comuni o che richiedano modificatori di accesso diversi da quelli pubblici (come protetti e privati).
  3. Si desidera dichiarare campi non statici o non finali.

Prendi in considerazione l'utilizzo di interfacce se:

  1. Ti aspetti che le classi non correlate implementino la tua interfaccia. Ad esempio, molti oggetti non correlati possono implementare l' Serializableinterfaccia.
  2. Vuoi specificare il comportamento di un particolare tipo di dati, ma non preoccuparti di chi lo implementa.
  3. Vuoi sfruttare l'ereditarietà multipla di tipo.

Esempio:

Classe astratta ( relazione IS A )

Reader è una classe astratta.

BufferedReader è unReader

FileReader è aReader

FileReadere BufferedReadersono utilizzati per scopi comuni: lettura dei dati e sono correlati attraverso la Readerclasse.

Interfaccia (ha una capacità)

Serializable è un'interfaccia.

Supponi di avere due classi nella tua applicazione, che stanno implementando l' Serializableinterfaccia

Employee implements Serializable

Game implements Serializable

Qui non è possibile stabilire alcuna relazione attraverso l' Serializableinterfaccia tra Employeee Game, che sono pensati per scopi diversi. Entrambi sono in grado di serializzare lo stato e la comparazione finisce lì.

Dai un'occhiata a questi post:

Come avrei dovuto spiegare la differenza tra un'interfaccia e una classe astratta?


40

OK, dopo averlo "sgridato" da solo - eccolo in parole povere (sentiti libero di correggermi se sbaglio) - So che questo argomento è oooooold, ma qualcun altro potrebbe inciampare un giorno ...

Le classi astratte ti consentono di creare un progetto e ti consentono inoltre di COSTRUIRE (implementare) proprietà e metodi che desideri possedere TUTTI i suoi discendenti.

Un'interfaccia invece ti consente solo di dichiarare che vuoi che esistano proprietà e / o metodi con un determinato nome in tutte le classi che lo implementano, ma non specifica come dovresti implementarlo. Inoltre, una classe può implementare MOLTE interfacce, ma può estendere solo UNA classe astratta. Un'interfaccia è più uno strumento architettonico di alto livello (che diventa più chiaro se inizi a cogliere i modelli di progettazione): un abstract ha un piede in entrambi i campi e può eseguire anche parte del lavoro sporco.

Perché usarne uno sopra l'altro? Il primo consente una definizione più concreta dei discendenti, il secondo consente un maggiore polimorfismo . Quest'ultimo punto è importante per l'utente finale / programmatore, che può utilizzare queste informazioni per implementare l'AP I (interfaccia) in una varietà di combinazioni / forme per soddisfare le loro esigenze.

Penso che questo sia stato il momento della "lampadina" per me - pensa alle interfacce meno dalla prospettiva dell'autore e più da quella di qualsiasi programmatore che verrà più avanti nella catena che sta aggiungendo l'implementazione a un progetto o estendendo un'API.


basarsi su questo: un oggetto che implementa un'interfaccia assume il suo TIPO. Questo è cruciale. Quindi, puoi passare diverse varianti dell'interfaccia a una classe, ma fai riferimento a loro (e ai loro metodi) CON IL NOME TIPO DELL'INTERFACCIA. Pertanto, si elimina la necessità di un interruttore o di un ciclo if / else. Prova questo tutorial sull'argomento: dimostra l'uso di un'interfaccia tramite il modello di strategia. phpfreaks.com/tutorial/design-patterns---strategy-and-bridge/…
sunwukung

Concordo pienamente sul tuo momento della lampadina: "API (nterface) in una varietà di combinazioni / forme per soddisfare le loro esigenze"! Ottimo punto da fare.
Trevor Boyd Smith,

39

I miei due centesimi:

Un'interfaccia in sostanza definisce un contratto a cui qualsiasi classe di implementazione deve aderire (implementare i membri dell'interfaccia). Non contiene alcun codice.

D'altra parte, una classe astratta può contenere codice e potrebbero esserci alcuni metodi contrassegnati come astratti che una classe ereditaria deve implementare.

Le rare situazioni in cui ho usato le classi astratte sono quando ho alcune funzionalità predefinite che la classe ereditaria potrebbe non essere interessante nel sovrascrivere, per esempio una classe base astratta, da cui ereditano alcune classi specializzate.

Esempio (uno molto rudimentale!): Si consideri una chiamata clienti classe di base che ha i metodi astratti come CalculatePayment(), CalculateRewardPoints()e alcuni metodi non astratti come GetName(), SavePaymentDetails().

Classi specializzate come RegularCustomer e GoldCustomererediteranno dalla Customerclasse base e implementeranno la propria logica CalculatePayment()e CalculateRewardPoints()metodo, ma riutilizzeranno i metodi GetName()e SavePaymentDetails().

È possibile aggiungere più funzionalità a una classe astratta (ovvero metodi non astratti) senza influire sulle classi figlio che utilizzavano una versione precedente. Considerando che l'aggiunta di metodi a un'interfaccia influirebbe su tutte le classi che la implementano poiché ora dovrebbero implementare i membri dell'interfaccia appena aggiunti.

Una classe astratta con tutti i membri astratti sarebbe simile a un'interfaccia.


1
+1 per "È possibile aggiungere più funzionalità a una classe astratta (ovvero metodi non astratti) senza influire sulle classi figlio che utilizzavano una versione precedente. Considerando che l'aggiunta di metodi a un'interfaccia influirebbe su tutte le classi che la implementano poiché ora dovrebbero implementare i membri dell'interfaccia appena aggiunti. "
Div Tiwari,

le interfacce possono avere metodi "predefiniti", quindi non avere un metodo impl nelle interfacce è un'idea sbagliata. La relazione IS-A "Parent-to-Child" è la chiave qui. Inoltre, "Attributi condivisi" vs. "Proprietà condivise". ad es. Cane iS-A Animale. Ma un cane può anche "Camminare"
ha9u63ar, il

30

Quando fare ciò che è una cosa molto semplice se hai in mente il concetto chiaro.

Le classi astratte possono essere derivate mentre le interfacce possono essere implementate. C'è qualche differenza tra i due. Quando derivate una classe astratta, la relazione tra la classe derivata e la classe base è 'è una relazione'. ad esempio, un cane è un animale, una pecora è un animale, il che significa che una classe derivata eredita alcune proprietà dalla classe base.

Considerando che per l'implementazione di interfacce, la relazione è "può essere". ad esempio, un cane può essere un cane spia. Un cane può essere un cane da circo. Un cane può essere un cane da corsa. Ciò significa che si implementano determinati metodi per acquisire qualcosa.

Spero di essere chiaro.


11

1.Se stai creando qualcosa che fornisce funzionalità comuni a classi non correlate, usa un'interfaccia.

2.Se stai creando qualcosa per oggetti strettamente correlati in una gerarchia, usa una classe astratta.



7

Penso che il modo più conciso di dirlo sia il seguente:

Proprietà condivise => classe astratta.
Funzionalità condivisa => interfaccia.

E per dirla in modo meno succinto ...

Esempio di classe astratta:

public abstract class BaseAnimal
{
    public int NumberOfLegs { get; set; }

    protected BaseAnimal(int numberOfLegs)
    {
        NumberOfLegs = numberOfLegs;
    }
}

public class Dog : BaseAnimal
{
    public Dog() : base(4) { }
}

public class Human : BaseAnimal 
{
    public Human() : base(2) { }
}

Poiché gli animali hanno una proprietà condivisa - il numero di zampe in questo caso - ha senso creare una classe astratta contenente questa proprietà condivisa. Questo ci consente anche di scrivere codice comune che opera su quella proprietà. Per esempio:

public static int CountAllLegs(List<BaseAnimal> animals)
{
    int legCount = 0;
    foreach (BaseAnimal animal in animals)
    {
        legCount += animal.NumberOfLegs;
    }
    return legCount;
}

Esempio di interfaccia:

public interface IMakeSound
{
    void MakeSound();
}

public class Car : IMakeSound
{
    public void MakeSound() => Console.WriteLine("Vroom!");
}

public class Vuvuzela : IMakeSound
{
    public void MakeSound() => Console.WriteLine("VZZZZZZZZZZZZZ!");        
}

Nota qui che Vuvuzelas e Cars sono cose completamente diverse, ma hanno funzionalità condivise: produrre un suono. Pertanto, un'interfaccia ha senso qui. Inoltre, consentirà ai programmatori di raggruppare cose che emettono suoni in un'unica interfaccia, IMakeSoundin questo caso. Con questo disegno, potresti scrivere il seguente codice:

List<IMakeSound> soundMakers = new List<ImakeSound>();
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Vuvuzela());

foreach (IMakeSound soundMaker in soundMakers)
{
    soundMaker.MakeSound();
}

Puoi dire cosa sarebbe uscita?

Infine, puoi combinare i due.

Esempio combinato:

public interface IMakeSound
{
    void MakeSound();
}

public abstract class BaseAnimal : IMakeSound
{
    public int NumberOfLegs { get; set; }

    protected BaseAnimal(int numberOfLegs)
    {
        NumberOfLegs = numberOfLegs;
    }

    public abstract void MakeSound();
}

public class Cat : BaseAnimal
{
    public Cat() : base(4) { }

    public override void MakeSound() => Console.WriteLine("Meow!");
}

public class Human : BaseAnimal 
{
    public Human() : base(2) { }

    public override void MakeSound() => Console.WriteLine("Hello, world!");
}

Qui, richiediamo che tutti BaseAnimalemettano un suono, ma non ne conosciamo ancora l'implementazione. In tal caso, possiamo astrarre l'implementazione dell'interfaccia e delegarne l'implementazione alle sue sottoclassi.

Un ultimo punto, ricordi come nell'esempio di classe astratto siamo stati in grado di operare sulle proprietà condivise di oggetti diversi e nell'esempio di interfaccia siamo stati in grado di invocare la funzionalità condivisa di oggetti diversi? In questo ultimo esempio, potremmo fare entrambe le cose.


7

Quando preferire una classe astratta rispetto all'interfaccia?

  1. Se si prevede di aggiornare una classe base per tutta la durata di un programma / progetto, è meglio consentire che la classe base sia una classe astratta
  2. Se si sta cercando di costruire una spina dorsale per oggetti che sono strettamente correlati in una gerarchia, è molto utile usare una classe astratta

Quando preferire un'interfaccia rispetto alla classe astratta?

  1. Se uno non ha a che fare con un enorme tipo di struttura gerarchica, le interfacce sarebbero un'ottima scelta
  2. Poiché l'ereditarietà multipla non è supportata con le classi astratte (problema dei diamanti), le interfacce possono salvare la situazione

Cosa ti ha fatto pensare che una domanda vecchia di quasi dieci anni avesse bisogno di una 22a risposta?
jonrsharpe,

3
Lo stesso tipo di pensiero che mi ha fatto cercare una risposta semplice alla domanda.
Satya,

1
FWIW, adoro davvero questa risposta.
Brent Rittenhouse,

6

Le classi possono ereditare da una sola classe base, quindi se si desidera utilizzare classi astratte per fornire polimorfismo a un gruppo di classi, devono ereditare tutte da quella classe. Le classi astratte possono anche fornire membri che sono già stati implementati. Pertanto, è possibile garantire una certa quantità di funzionalità identiche con una classe astratta, ma non con un'interfaccia.

Ecco alcuni consigli per aiutarti a decidere se utilizzare un'interfaccia o una classe astratta per fornire polimorfismo per i tuoi componenti.

  • Se prevedi di creare più versioni del tuo componente, crea una classe astratta. Le classi astratte offrono un modo semplice e semplice per eseguire la versione dei componenti. Aggiornando la classe base, tutte le classi ereditarie vengono automaticamente aggiornate con la modifica. Le interfacce, d'altra parte, non possono essere modificate una volta create in quel modo. Se è necessaria una nuova versione di un'interfaccia, è necessario creare un'interfaccia completamente nuova.
  • Se la funzionalità che stai creando sarà utile su una vasta gamma di oggetti diversi, usa un'interfaccia. Le classi astratte dovrebbero essere utilizzate principalmente per oggetti strettamente correlati, mentre le interfacce sono più adatte a fornire funzionalità comuni a classi non correlate.
  • Se stai progettando piccole funzionalità concise, usa le interfacce. Se si progettano unità funzionali di grandi dimensioni, utilizzare una classe astratta.
  • Se si desidera fornire funzionalità comuni e implementate tra tutte le implementazioni del componente, utilizzare una classe astratta. Le classi astratte ti consentono di implementare parzialmente la tua classe, mentre le interfacce non contengono implementazioni per nessun membro.

Copiato da:
http://msdn.microsoft.com/en-us/library/scsyfw1d%28v=vs.71%29.aspx


Non c'è nulla in UML che preclude l'eredità di più classi. L'ereditarietà multipla è determinata da un linguaggio di programmazione, non da UML. Ad esempio, l'eredità di più classi non è consentita in Java e C #, ma è consentita in C ++.
BobRodes

@BobRodes: sono disponibili numerose funzionalità che i framework orientati agli oggetti possono fornire in varie combinazioni, ma non in tutte le combinazioni. L'ereditarietà multipla generalizzata preclude alcune altre utili combinazioni di funzioni tra cui la possibilità di trasmettere un riferimento direttamente a qualsiasi tipo di genitore dell'istanza effettiva o qualsiasi tipo di interfaccia supportato in tal modo e la possibilità di compilare in modo indipendente tipi di base e tipi derivati ​​e unirli in fase di esecuzione.
Supercat,

@supercat Yours è una buona spiegazione di alcuni dei problemi derivanti dall'utilizzo dell'ereditarietà multipla. Tuttavia, non esiste nulla in UML che precluda l'ereditarietà di più classi in un diagramma. Stavo rispondendo a quanto sopra "Le classi possono ereditare da una sola classe base ..." che non è proprio così.
BobRodes,

@BobRodes: la domanda è stata taggata Java. Java include le funzionalità indicate e quindi è limitato a forme di eredità multipla che non possono produrre un "diamante mortale" (anche se in realtà il modo in cui hanno implementato implementazioni di interfaccia predefinite rende possibile il diamante mortale).
supercat,

@supercat Oh, ok. Di solito non guardo i tag java, quindi al momento in cui ho scritto che almeno pensavo di commentare una risposta UML. In ogni caso, sono d'accordo con il tuo commento.
BobRodes

3

Prendi in considerazione l'uso di classi astratte se una di queste affermazioni si applica alla tua situazione:

  1. Vuoi condividere il codice tra diverse classi strettamente correlate.
  2. Ti aspetti che le classi che estendono la tua classe astratta abbiano molti metodi o campi comuni o richiedano modificatori di accesso diversi da quelli pubblici (come protetti e privati).
  3. Si desidera dichiarare campi non statici o non finali. Ciò consente di definire metodi che possono accedere e modificare lo stato dell'oggetto a cui appartengono.

Prendi in considerazione l'utilizzo di interfacce se una di queste affermazioni si applica alla tua situazione:

  1. Ti aspetti che le classi non correlate implementino la tua interfaccia. Ad esempio, le interfacce Comparable e Cloneable sono implementate da molte classi non correlate.
  2. Vuoi specificare il comportamento di un particolare tipo di dati, ma non preoccuparti di chi lo implementa.
  3. Vuoi sfruttare molteplici eredità.

fonte


2

Le risposte variano tra le lingue. Ad esempio, in Java una classe può implementare (ereditare da) più interfacce ma ereditare solo da una classe astratta. Quindi le interfacce ti offrono maggiore flessibilità. Ma questo non è vero in C ++.


2

Per me, andrei con le interfacce in molti casi. Ma preferisco lezioni astratte in alcuni casi.

Le classi in OO si riferiscono generalmente all'implementazione. Uso le classi astratte quando voglio forzare alcuni dettagli di implementazione ai bambini, altrimenti vado con le interfacce.

Naturalmente, le classi astratte sono utili non solo per forzare l'implementazione, ma anche per condividere alcuni dettagli specifici tra molte classi correlate.


1

Utilizzare una classe astratta se si desidera fornire alcune implementazioni di base.


1
Grazie Sebastian. E se non avessi bisogno di un'implementazione di base? Una classe e un'interfaccia astratte non saranno le stesse allora se questa è l'unica differenza tra loro? Perché c'è una differenza?
Chirantan,

1
Perché alcune lingue non hanno interfacce - C ++.
jmucchiello,

1

in java puoi ereditare da una classe (astratta) per "fornire" funzionalità e puoi implementare molte interfacce per "garantire" la funzionalità


piccolo suggerimento: se vuoi ereditare da una classe astratta e un'interfaccia, assicurati che la classe astratta implementa l'interfaccia
Andreas Niedermair,

1

Puramente sulla base dell'eredità, useresti un Estratto in cui stai definendo relazioni chiaramente discendenti e astratte (cioè animale-> gatto) e / o richiedi l'eredità di proprietà virtuali o non pubbliche, in particolare lo stato condiviso (che le interfacce non possono supportare ).

Dovresti cercare di favorire la composizione (tramite iniezione di dipendenza) rispetto all'ereditarietà dove puoi, e notare che le interfacce essendo contratti supportano unit test, separazione delle preoccupazioni e (variazione della lingua) l'ereditarietà multipla in un modo che gli Abstracts non possono.


1

Una posizione interessante in cui le interfacce funzionano meglio delle classi astratte è quando è necessario aggiungere funzionalità extra a un gruppo di oggetti (correlati o non correlati). Se non puoi dare loro una classe astratta di base (ad esempio, sono sealedo hanno già un genitore), puoi invece dare loro un'interfaccia fittizia (vuota) e quindi semplicemente scrivere metodi di estensione per quell'interfaccia.


0

Questa può essere una chiamata molto difficile da fare ...

Un puntatore che posso dare: un oggetto può implementare molte interfacce, mentre un oggetto può ereditare solo una classe di base (in un linguaggio OO moderno come c #, so che C ++ ha eredità multipla - ma non è disapprovato?)


L'ereditarietà multipla consente l'implementazione di Mixin in modo apparente, i Mixin ben scritti sono un gioco da ragazzi ma molto difficili da trovare e difficili da scrivere senza essere a corto di spazio. I Mixin sono piuttosto fantastici nel loro complesso anche se IMO.
Martijn Laarman,

In realtà non l'ho fatto, l'ereditarietà multipla è davvero uno stimolo di dibattito sicuro tra noi geek, non vedo assolutamente alcun motivo per votare. In effetti ho votato la tua risposta.
Martijn Laarman,

L'unico punto che ho cercato di sottolineare è che sono possibili anche modi per mixare in lingue con Single Ereditarietà (C #, PHP, javascript) ma attraverso comportamenti confusi o sintassi pacchiana. Adoro i Mixin quando funzionano, ma sono ancora incerto su chi eredita o meno su eredità multipla.
Martijn Laarman,

Questa risposta è più una differenza sintattica che una differenza progettuale. Penso che stia chiedendo una differenza di design
Pramod Setlur

0

Una classe astratta può avere implementazioni.

Un'interfaccia non ha implementazioni, definisce semplicemente una specie di contratto.

Possono esserci anche alcune differenze dipendenti dalla lingua: ad esempio C # non ha ereditarietà multipla, ma in una classe possono essere implementate più interfacce.


Quando dici "una specie di contratto", intendi come nei servizi web?
Chirantan,

Tecnicamente parlando, i servizi web non funzionano con le interfacce. Con contratto intendo che l'utente di un oggetto sa quali metodi sono presenti su quell'oggetto. Ad esempio un'interfaccia IMouse avrà un metodo Move e un evento pulsante sinistro e destro del mouse.
Gerrie Schenck,

-1

La regola di base del pollice è: per "Nomi" usa la classe astratta e per "Verbi" usa l'interfaccia

Ad esempio: carè una classe astratta e drivepossiamo renderla un'interfaccia.


5
Questo non ha senso, possiamo anche mettere la funzionalità drivein macchina - questa è una classe astratta.
Arslan Ali,
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.