Perché dovrei dichiarare una classe come una classe astratta?

39

Conosco la sintassi, le regole applicate alla classe astratta e voglio conoscere l'utilizzo di una classe astratta

Abstract class can not be instantiated directly but can be extended by other class

Qual è il vantaggio di farlo?

Come è diverso da un'interfaccia?

So che una classe può implementare più interfacce ma può estendere solo una classe astratta. Questa è solo la differenza tra un'interfaccia e una classe astratta?

Sono a conoscenza dell'uso di un'interfaccia. Ho imparato che dal modello di delega di eventi di AWT in Java.

In quali situazioni dovrei dichiarare la classe come una classe astratta? Quali sono i vantaggi di questo?

    
posta Vaibhav Jani 29.07.2011 - 10:59
fonte

9 risposte

48

Questa risposta fa un buon lavoro di spiegazione delle differenze tra una classe astratta e un'interfaccia, ma non risponde perché dovresti dichiararne uno.

Da un punto di vista puramente tecnico, non esiste mai un requisito per dichiarare una classe come astratta.

Considera le seguenti tre classi:

class Database { 
    public String[] getTableNames() { return null; } //or throw an exception? who knows...
}

class SqlDatabase extends Database { } //TODO: override getTableNames

class OracleDatabase extends Database { }  //TODO: override getTableNames

Non avere per rendere astratta la classe Database, anche se c'è un problema evidente con la sua implementazione: quando stai scrivendo questo programma, potresti digitare new Database() e sarebbe valido, ma non funzionerebbe mai.

Indipendentemente, si otterrebbe comunque il polimorfismo, quindi se il tuo programma crea solo SqlDatabase e OracleDatabase istanze, potresti scrivere metodi come:

public void printTableNames(Database database) {
    String[] names = database.getTableNames();
}

Le classi astratte migliorano la situazione impedendo ad uno sviluppatore di creare un'istanza della classe base, perché lo sviluppatore ha contrassegnato come mancante di funzionalità . Fornisce inoltre sicurezza in fase di compilazione in modo che tu possa garantire che tutte le classi che estendono la tua classe astratta forniscano la funzionalità minima necessaria per funzionare e non devi preoccuparti di mettere i metodi di stub (come il uno sopra) che gli eredi in qualche modo devono sapere magicamente che hanno di sovrascrivere un metodo per farlo funzionare.

Interfacce sono un argomento completamente separato. Un'interfaccia ti consente di descrivere quali operazioni possono essere eseguite su un oggetto. Normalmente utilizzi le interfacce quando scrivi metodi, componenti, ecc. Che usano i servizi di altri componenti, oggetti, ma non ti interessa quale sia l'effettivo tipo di oggetto da cui stai ricevendo i servizi.

Considera il seguente metodo:

public void saveToDatabase(IProductDatabase database) {
     database.addProduct(this.getName(), this.getPrice());
}

Non ti importa se l'oggetto database eredita da un particolare oggetto, ti interessa solo che abbia un metodo addProduct . Quindi, in questo caso, un'interfaccia è più adatta rispetto a far sì che tutte le tue classi capiscano di ereditare dalla stessa classe base.

A volte la combinazione dei due funziona molto bene. Ad esempio:

abstract class RemoteDatabase implements IProductDatabase { 
    public abstract String[] connect();
    public abstract void writeRow(string col1, string col2);

    public void addProduct(String name, Double price) {
        connect();
        writeRow(name, price.toString());
    }
}

class SqlDatabase extends RemoteDatabase {
    //TODO override connect and writeRow
}

class OracleDatabase extends RemoteDatabase { 
    //TODO override connect and writeRow
}

class FileDatabase implements IProductDatabase {
    public void addProduct(String name, Double price) {
         //TODO: just write to file
    }
}

Si noti come alcuni database ereditino da RemoteDatabase per condividere alcune funzionalità (come la connessione prima di scrivere una riga), ma FileDatabase è una classe separata che implementa solo IProductDatabase .

    
risposta data 13.06.2012 - 22:12
fonte
15

Somiglianze

Per l'astrazione sono richieste classi e interfacce astratte. Non possono essere istanziati con un nuovo , ma è possibile risolverlo in inversione dei contenitori di controllo o tramite modelli di fabbrica.

Differenza

  1. Interfacce

    • Definisci un contratto pubblico ben noto, abilità del tipo
    • Applicabile per mostrare l'ereditarietà orizzontale, ovvero la ramificazione sul primo livello di ereditarietà (ad esempio ILog per definire le strutture di registrazione su database, file di testo, XML, SOAP ecc.)
    • Tutti i membri sono pubblici
    • Nessuna implementazione consentita
    • Il bambino per l'ereditarietà può avere molte interfacce per implementare
    • Utile per l'integrazione di terze parti
    • Il naming di solito inizia con I
  2. Classe astratta

    • Definisci la struttura, l'identità e alcuni comportamenti di default supportati
    • Applicabile per mostrare l'ereditarietà verticale, cioè la ramificazione profonda sui vari livelli (ad esempio, classe AbstractEntity nello sviluppo basato su domini)
    • I membri possono avere visibilità diversa (da pubblico a privato)
    • Puoi implementare alcuni membri (ad es. * Classi di lettori)
    • Il figlio di ereditarietà può avere solo una classe astratta di base

In realtà è facile trovare la risposta semplice query su google .

    
risposta data 29.07.2011 - 11:31
fonte
11

How it is different from an Interface?

In una classe astratta, è possibile implementare alcuni metodi e lasciare (forzare) il resto per essere implementato dalla classe estesa. Non è possibile implementare metodi in un'interfaccia. Non puoi costringere nessuno a scavalcare qualcosa quando estendi una classe ordinaria. Con una classe astratta, puoi.

    
risposta data 29.07.2011 - 11:08
fonte
8

Le classi astratte sono per "è un" relazioni e le interfacce sono per "può fare".

Le classi astratte ti consentono di aggiungere un comportamento di base in modo che i programmatori non debbano codificare tutto, mentre ancora li costringono a seguire il tuo progetto.

    
risposta data 16.08.2012 - 15:00
fonte
3

Oltre ai dettagli tecnici profondi - come l'implementazione di alcuni metodi per classi astratte, ecc., il significato è simile a questo:

Le interfacce definiscono la capacità comune - IEnumerable definisce che la classe che implementa questa interfaccia può essere enumerata. Non dice nulla sulla classe stessa.

Le classi astratte (o base) definiscono il comportamento - WebRequest definisce un comportamento comune di tutte le classi figlie come HttpWebRequest, ecc. Definisce il significato principale della classe ed è un vero scopo: accedere alle risorse web.

    
risposta data 29.07.2011 - 18:23
fonte
2

voce di Wikipedia .

Le principali differenze tra un'interfaccia e una classe astratta è che una classe astratta può fornire metodi implementati. Con le interfacce puoi solo dichiarare metodi, scrivere la loro firma. Ecco un esempio di una classe che estende una classe astratta che implementa due interfacce: (java)

interface MyInterface1 {
  string getValue1();
}

interface MyInterface2 {
  string getValue2();
}

abstract class MyAbstractClass implements MyInterface1, MyInterface2{
  void printValues() {
    System.out.println("Value 1: " + getValue1() + ", Value 2: " + getValue2() + 
                       ", Value 3: " + getValue3());
  }

  protected abstract string getValue3();
}

class ImpClass extends MyAbstractClass {
  public string getValue1() {
    return "1";
  }

  public string getValue2() {
    return "2";
  }

  protected string getValue3() {
    return "3";
  }
}

In questo esempio, MyAbstractClass fornisce un metodo pubblico che stampa tutti e tre i valori. In ImpClass devi implementare getValue1 e getValue2 rispettivamente da MyInterface1 e MyInterface2 e getValue3 dalla classe astratta.

Voilà.

Ci sono altri aspetti (interfaccia: solo metodi pubblici, classe astratta: metodi astratti e pubblici astratti protetti) ma puoi leggerlo da solo.

In una nota finale, una classe astratta che fornisce solo metodi astratti è una classe di base astratta "pura", ovvero un'interfaccia.

    
risposta data 29.07.2011 - 11:17
fonte
2
  • Interfaccia - quando alcune classi condividono un'API (nomi e parametri di metodo)
  • Classe astratta - quando alcune classi condividono lo stesso codice (implementazione)

In altre parole, dovresti iniziare con una domanda: "queste classi necessariamente condividono l'implementazione , oppure hanno solo un'interfaccia comune?"

Se la risposta è mista, ad esempio - queste tre classi devono condividere l'implementazione, ma queste altre due condividono solo la loro API - quindi puoi creare un'interfaccia per tutte e cinque e una classe astratta per queste tre con il codice comune.

Esistono anche altri modi per condividere l'implementazione, ad esempio per incapsulare un oggetto con tale implementazione (ad esempio nel strategia ).

    
risposta data 17.08.2012 - 10:35
fonte
1

Dichiareresti un abstract di classe quando non vuoi che lo sviluppatore (probabilmente te stesso) possa istanziarlo, perché non funzionerebbe o non avrebbe senso.

Ad esempio, considera un gioco in cui esistono diversi tipi di entità di gioco. Tutti ereditano dalla classe GameEntity di base.

abstract class GameEntity{

    int lifePoint, speed, damage;

    public attack(GameEntity target){ target.damage(damage); }

    public damage(int damageInflicted){ lifePoint -= damageInflicted - speed; }

    // etc...

}

Questa classe è dichiarata abstract poiché non avrebbe senso istanziarla. Dichiara alcune azioni per le entità di gioco e alcuni attributi, ma da nessuna parte in questa classe vengono inizializzati questi attributi. Questa classe funge da modello per le entità di gioco, ma non è pensata per essere istanziata da sola, e come tale dichiarata abstract .

Per quanto riguarda la differenza di utilizzo tra una classe astratta e un'interfaccia:

Come vedo, un'interfaccia è un modo per ottenere un comportamento polimorfico senza essere limitato dal meccanismo di ereditarietà di alcuni linguaggi.

Torniamo al gioco come esempio. Considera una classe Enemy derivata da GameEntity . Questa classe ha un metodo attackMeFromDistance(RangedAttacker attacker) . Questo metodo ha lo scopo di consentire alle entità di attaccare il nemico da lontano.

Come puoi vedere, questo metodo accetta un parametro RangedAttacker come parametro. Tuttavia, tutte le entità di gioco ereditano già da GameEntity . Non possono estendere un'altra classe.

Prendi le classi Mage e Archer per esempio. Vogliamo consentire ad entrambi di essere accettati come parametri nel metodo attackMeFromDistance(RangedAttacker attacker) , ma sono già derivati da GameEntity .

Per risolvere questo problema, creiamo una nuova interfaccia:

interface RangedAttacker{
    public void attackFromDistance();
}

Una classe che implementa questa interfaccia deve implementare il metodo attackFromDistance() , e quindi è garantito che abbia funzionalità di attacco a distanza. Ciò significa che il metodo attackMeFromDistance ora può tranquillamente accettare classi che implementano questa interfaccia. Pertanto, implementando Mage e Archer , l'interfaccia risolve il nostro problema.

Per me, questa è la potenza delle interfacce.

Quindi, per riassumere, di solito usi una classe astratta quando vuoi avere una classe base per alcune classi, ma non avrebbe senso istanziarla da sola (o nel caso in cui abbia abstract metodi, che devono essere implementati dalle sottoclassi, e in questo caso il compilatore farebbe rispettare la classe abstract ). Dovresti usare un'interfaccia per ottenere un comportamento polimorfico senza essere limitato dal meccanismo di ereditarietà.

    
risposta data 14.04.2014 - 12:40
fonte
0
  1. C'è la possibilità che pochi metodi siano comuni ad alcune classi (business logic). E i metodi rimanenti sono diversi. In questo tipo di scenari è possibile implementare tutti i metodi comuni in una classe e dichiarare i rimanenti come astratti. Quindi dovresti dichiarare la classe come astratta.
  2. A volte non è consentito creare direttamente l'oggetto nella classe. Quel tipo di classe devi dichiarare la classe come astratta.
risposta data 12.10.2012 - 20:34
fonte

Leggi altre domande sui tag