it-swarm.dev

Warum sollte ich eine Klasse als abstrakte Klasse deklarieren?

Ich kenne die Syntax, die Regeln für abstrakte Klassen und möchte die Verwendung einer abstrakten Klasse kennen

Abstrakte Klassen können nicht direkt instanziiert, sondern um andere Klassen erweitert werden

Was ist der Vorteil davon?

Wie unterscheidet es sich von einer Schnittstelle?

Ich weiß, dass eine Klasse mehrere Schnittstellen implementieren kann, aber nur eine abstrakte Klasse erweitern kann. Ist das nur ein Unterschied zwischen einer Schnittstelle und einer abstrakten Klasse?

Mir ist die Verwendung einer Schnittstelle bekannt. Ich habe das aus dem Ereignisdelegationsmodell von AWT in Java gelernt.

In welchen Situationen sollte ich die Klasse als abstrakte Klasse deklarieren? Was bringt das?

40
Vaibhav Jani

Diese Antwort erklärt die Unterschiede zwischen einer abstrakten Klasse und einer Schnittstelle gut, aber sie antwortet nicht warum Sie eine deklarieren sollten.

Aus rein technischer Sicht gibt es niemals eine Anforderung , eine Klasse als abstrakt zu deklarieren.

Betrachten Sie die folgenden drei Klassen:

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

Sie müssen nicht , um die Datenbankklasse abstrakt zu machen, obwohl es ein offensichtliches Problem bei ihrer Implementierung gibt: Wenn Sie dieses Programm schreiben, könnten Sie Geben Sie new Database() ein und es wäre gültig, aber es würde niemals funktionieren.

Unabhängig davon würden Sie immer noch Polymorphismus erhalten. Solange Ihr Programm nur Instanzen SqlDatabase und OracleDatabase erstellt, können Sie Methoden wie die folgenden schreiben:

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

Abstrakte Klassen verbessern die Situation, indem sie verhindern, dass ein Entwickler die Basisklasse instanziiert, da ein Entwickler sie als markiert hat fehlende Funktionalität . Es bietet auch Sicherheit zur Kompilierungszeit , sodass Sie sicherstellen können, dass alle Klassen, die Ihre abstrakte Klasse erweitern, die Mindestfunktionalität für die Arbeit bieten, und Sie nicht. Sie müssen sich keine Gedanken über das Setzen von Stub-Methoden (wie die oben beschriebene) machen, die Erben auf magische Weise wissen müssen, dass sie eine Methode überschreiben müssen, um sie zu erstellen es funktioniert.

Schnittstellen sind ein völlig separates Thema. Über eine Schnittstelle können Sie beschreiben, welche Operationen an einem Objekt ausgeführt werden können. Normalerweise verwenden Sie Schnittstellen, wenn Sie Methoden, Komponenten usw. schreiben, die die Dienste anderer Komponenten, Objekte verwenden, aber es ist Ihnen egal, von welchem ​​Objekttyp Sie die Dienste tatsächlich erhalten.

Betrachten Sie die folgende Methode:

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

Es ist Ihnen egal, ob das database -Objekt von einem bestimmten Objekt erbt, Sie kümmern sich nur darum, dass es eine addProduct -Methode hat. In diesem Fall ist eine Schnittstelle besser geeignet, als alle Klassen von derselben Basisklasse zu erben.

Manchmal funktioniert die Kombination der beiden sehr gut. Zum Beispiel:

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
    }
}

Beachten Sie, wie einige der Datenbanken von RemoteDatabase erben, um einige Funktionen gemeinsam zu nutzen (z. B. das Herstellen einer Verbindung vor dem Schreiben einer Zeile). FileDatabase ist jedoch eine separate Klasse, die nur IProductDatabase implementiert.

50
Kevin McCormick

Ähnlichkeiten

Für die Abstraktion werden abstrakte Klassen und Schnittstellen benötigt. Sie können nicht mit einem neuen instanziiert werden, sondern können in Inversion von Kontrollcontainern oder über Factory-Muster aufgelöst werden.

Unterschied

  1. Schnittstellen

    • Definieren Sie bekannte öffentliche Aufträge, Fähigkeiten des Typs
    • Anwendbar zum Anzeigen der horizontalen Vererbung, d. H. Verzweigen auf der ersten Vererbungsebene (z. B. ILog zum Definieren von Protokollierungsfunktionen für Datenbank, Textdatei, XML, SOAP usw.)
    • Alle Mitglieder sind öffentlich
    • Keine Implementierung erlaubt
    • Vererbungskind kann viele Schnittstellen implementieren
    • Nützlich für die Integration von Drittanbietern
    • Die Benennung beginnt normalerweise mit [~ # ~] i [~ # ~]
  2. Abstrakte Klasse

    • Definieren Sie Struktur, Identität und einige standardmäßig unterstützte Verhaltensweisen
    • Anwendbar, um vertikale Vererbung zu zeigen, d. H. Tiefe Verzweigung auf den verschiedenen Ebenen (z. B. AbstractEntity-Klasse in domänengetriebener Entwicklung)
    • Mitglieder können unterschiedliche Sichtbarkeit haben (von öffentlich zu privat)
    • Sie können einige Mitglieder implementieren (z. B. * Reader-Klassen).
    • Vererbungskind kann nur eine abstrakte Basisklasse haben

Es ist tatsächlich einfach, die Antwort mit einfache Google-Abfrage zu finden.

16
oleksii

Wie unterscheidet es sich von einer Schnittstelle?

In einer abstrakten Klasse können Sie einige Methoden implementieren und den Rest von der erweiterten Klasse implementieren lassen. Sie können keine Methoden in einer Schnittstelle implementieren. Sie können niemanden zwingen, etwas zu überschreiben, wenn Sie eine normale Klasse erweitern. Mit einer abstrakten Klasse können Sie.

11
Joonas Pulakka

Abstrakte Klassen stehen für "is a" -Beziehungen und Schnittstellen für "can do".

Mit abstrakten Klassen können Sie das Basisverhalten hinzufügen, damit Programmierer nicht alles codieren müssen, während sie dennoch gezwungen werden, Ihrem Entwurf zu folgen.

8

Neben den tiefgreifenden technischen Details - wie der Implementierung einiger Methoden für abstrakte Klassen usw. - lautet die Bedeutung wie folgt:

Schnittstellen definieren gemeinsame Funktionen - IEnumerable definiert, dass die Klasse, die diese Schnittstelle implementiert, aufgelistet werden kann. Es sagt nichts über die Klasse selbst aus.

Abstrakte (oder Basis-) Klassen definieren das Verhalten - WebRequest definiert ein gemeinsames Verhalten aller untergeordneten Klassen wie HttpWebRequest usw. Es definiert die Kernbedeutung der Klasse und ihren eigentlichen Zweck - den Zugriff auf Webressourcen.

3
Sunny

Wikipedia-Eintrag .

Der Hauptunterschied zwischen einer Schnittstelle und einer abstrakten Klasse besteht darin, dass eine abstrakte Klasse implementierte Methoden bereitstellen kann. Mit Schnittstellen können Sie nur Methoden deklarieren, deren Signatur schreiben. Hier ist ein Beispiel für eine Klasse, die eine abstrakte Klasse erweitert, die zwei Schnittstellen implementiert: (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 diesem Beispiel bietet die MyAbstractClass eine öffentliche Methode, die alle drei Werte druckt. In ImpClass müssen Sie getValue1 bzw. getValue2 aus MyInterface1 und MyInterface2 und getValue3 aus dem Abstract implementieren Klasse.

Voilà.

Es gibt weitere Aspekte (Schnittstelle: nur öffentliche Methoden, abstrakte Klasse: geschützte abstrakte und öffentliche abstrakte Methoden), aber Sie können dies selbst lesen.

Schließlich ist eine abstrakte Klasse, die nur abstrakte Methoden bereitstellt, eine "reine" abstrakte Basisklasse, auch bekannt als Schnittstelle.

2
Jalayn
  • Schnittstelle - wenn einige Klassen eine API gemeinsam nutzen (Methodennamen und Parameter)
  • Abstrakte Klasse - wenn einige Klassen denselben Code verwenden (Implementierung)

Mit anderen Worten, Sie sollten mit einer Frage beginnen: "Teilen diese Klassen notwendigerweise die Implementierung oder haben sie nur eine gemeinsame Schnittstelle ? "

Wenn die Antwort gemischt ist, z. B. - diese drei Klassen müssen die Implementierung gemeinsam nutzen, diese beiden anderen jedoch nur ihre API -, können Sie eine Schnittstelle für alle fünf und eine abstrakte Klasse für diese drei Klassen mit der gemeinsamen Klasse erstellen Code.

Es gibt auch andere Möglichkeiten, die Implementierung gemeinsam zu nutzen, beispielsweise um ein Objekt mit dieser Implementierung zu kapseln (z. B. in Strategie Muster).

2
Viliam Búr

Sie würden eine Klassenzusammenfassung deklarieren, wenn Sie nicht möchten, dass der Entwickler (wahrscheinlich Sie selbst) sie instanziieren darf, weil sie nicht funktioniert oder keinen Sinn ergibt.

Stellen Sie sich zum Beispiel ein Spiel vor, bei dem es verschiedene Arten von Spieleinheiten gibt. Sie alle erben von der Basisklasse GameEntity.

abstract class GameEntity{

    int lifePoint, speed, damage;

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

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

    // etc...

}

Diese Klasse wird als abstract deklariert, da es keinen Sinn macht, sie zu instanziieren. Es werden einige Aktionen für die Spielentitäten und einige Attribute deklariert, aber nirgends in dieser Klasse werden diese Attribute initialisiert. Diese Klasse dient als Vorlage für die Spielentitäten, ist jedoch nicht dazu gedacht, selbst instanziiert zu werden, und deklariert als solche abstract.

In Bezug auf den Unterschied in der Verwendung zwischen einer abstrakten Klasse und einer Schnittstelle :

Aus meiner Sicht ist eine Schnittstelle eine Möglichkeit, polymorphes Verhalten zu erlangen, ohne durch den Einzelvererbungsmechanismus einiger Sprachen eingeschränkt zu sein.

Kehren wir als Beispiel zum Spiel zurück. Betrachten Sie eine Klasse Enemy, die von GameEntity abgeleitet ist. Diese Klasse hat eine Methode attackMeFromDistance(RangedAttacker attacker). Diese Methode soll es Entitäten ermöglichen, den Feind von weitem anzugreifen.

Wie Sie sehen können, verwendet diese Methode den Typ RangedAttacker als Parameter. Alle Spielentitäten erben jedoch bereits von GameEntity. Sie können keine andere Klasse erweitern.

Nehmen wir zum Beispiel die Klassen Mage und Archer. Wir möchten, dass beide als Parameter in der Methode attackMeFromDistance(RangedAttacker attacker) akzeptiert werden, aber sie sind bereits von GameEntity abgeleitet.

Um dies zu lösen, erstellen wir eine neue Schnittstelle:

interface RangedAttacker{
    public void attackFromDistance();
}

Eine Klasse, die diese Schnittstelle implementiert, muss die Methode attackFromDistance() implementieren, und daher wird sichergestellt, dass sie über Fernkampffähigkeiten verfügt. Dies bedeutet, dass die Methode attackMeFromDistance jetzt sicher Klassen akzeptieren kann, die diese Schnittstelle implementieren. Wenn Sie also Mage und Archer implementieren, um diese Schnittstelle zu implementieren, wird unser Problem gelöst.

Für mich ist dies die Kraft von Schnittstellen.

Zusammenfassend lässt sich sagen, dass Sie normalerweise eine abstrakte Klasse verwenden, wenn Sie eine Basisklasse für einige Klassen haben möchten, aber es wäre nicht sinnvoll, sie selbst zu instanziieren (oder in einem Fall, in dem abstract vorhanden ist) Methoden, die von den Unterklassen implementiert werden müssen, und in diesem Fall würde der Compiler Sie zwingen, die Klasse abstract) zu erstellen. Sie würden eine Schnittstelle verwenden, um polymorphes Verhalten zu erzielen, ohne durch den Einzelvererbungsmechanismus eingeschränkt zu sein.

1
Aviv Cohn
  1. Es besteht die Möglichkeit, dass einer Klasse zu wenige Methoden gemeinsam sind (Geschäftslogik). Und die übrigen Methoden sind unterschiedlich. In solchen Szenarien können Sie alle gängigen Methoden in einer Klasse implementieren und die verbleibenden als abstrakt deklarieren. Dann sollten Sie die Klasse als abstrakt deklarieren.
  2. Manchmal erlauben Sie nicht, das Objekt direkt für die Klasse zu erstellen. Diese Art von Klasse müssen Sie als abstrakt deklarieren.
0
Dharani Kumar