Schnittstelle oder eine abstrakte Klasse: welche verwenden?


327

Bitte erläutern Sie, wann ich ein PHP verwenden soll interfaceund wann ich ein abstract class?

Wie kann ich meine abstract classin eine ändern interface?

Antworten:


458

Verwenden Sie eine Schnittstelle, wenn Sie Entwickler, die in Ihrem System arbeiten (Sie selbst eingeschlossen), dazu zwingen möchten, eine festgelegte Anzahl von Methoden für die Klassen zu implementieren, die sie erstellen werden.

Verwenden Sie eine abstrakte Klasse, wenn Sie Entwickler, die in Ihrem System arbeiten (Sie selbst eingeschlossen), dazu zwingen möchten, eine festgelegte Anzahl von Methoden zu implementieren, und wenn Sie einige Basismethoden bereitstellen möchten, die ihnen bei der Entwicklung ihrer untergeordneten Klassen helfen.

Beachten Sie außerdem, dass Clientklassen nur eine abstrakte Klasse erweitern können, während sie mehrere Schnittstellen implementieren können. Wenn Sie also Ihre Verhaltensverträge in abstrakten Klassen definieren, bedeutet dies, dass jede untergeordnete Klasse möglicherweise nur einem einzigen Vertrag entspricht. Manchmal ist dies eine gute Sache, wenn Sie Ihre Benutzerprogrammierer auf einen bestimmten Pfad zwingen möchten. In anderen Fällen wäre es schlecht. Stellen Sie sich vor, die Countable- und Iterator-Schnittstellen von PHP wären abstrakte Klassen anstelle von Schnittstellen.

Ein Ansatz, der häufig verwendet wird, wenn Sie sich nicht sicher sind, welchen Weg Sie einschlagen sollen (wie von Cletus unten erwähnt ), besteht darin, eine Schnittstelle zu erstellen und diese Schnittstelle dann von Ihrer abstrakten Klasse implementieren zu lassen.


12
Ich habe den ganzen Tag versucht, die Verwendung abstractund den interfaceUnterricht zu verstehen. Ihr Beitrag hat alles klar gemacht. Vielen Dank Alan
afarazit

4
Ein weiterer Vorteil abstrakter Klassen ist die Möglichkeit, abstrakt geschützte Methoden zu definieren . Nicht immer nützlich, kann aber in einigen Architekturen nützlich sein.
Netcoder

In vielen Fällen sollten wir aus
Gründen

3
@volocuga: nicht unbedingt, wie Alan betonte, kann nur eine einzige Zusammenfassung erweitert werden. Ich persönlich mag es nicht, wenn die Zusammenfassung eine Schnittstellenidee implementiert, weil sie zur Verschleierung des Codes beiträgt und weniger direkt ist, IMO.
Präfix

171

Die Unterschiede zwischen einem Abstract Classund einem Interface:

Abstrakte Klassen

Eine abstrakte Klasse kann einige Funktionen bereitstellen und den Rest der abgeleiteten Klasse überlassen .

  • Die abgeleitete Klasse kann die in der Basisklasse definierten konkreten Funktionen überschreiben oder nicht .

  • Eine von einer abstrakten Klasse erweiterte untergeordnete Klasse sollte logisch verknüpft sein.

Schnittstelle

Eine Schnittstelle kann keine Funktionalität enthalten . Es enthält nur Definitionen der Methoden.

  • Die abgeleitete Klasse MUSS Code für alle in der Schnittstelle definierten Methoden bereitstellen .

  • Über eine Schnittstelle können völlig unterschiedliche und nicht verwandte Klassen logisch zusammengefasst werden.


1
Können Sie ein Beispiel aus dem wirklichen Leben liefern, um dies zu demonstrieren?
RN Kushwaha

1
Was ist der Unterschied zwischen abstract class X implements Yund class X implements Y?
Webinan

3
@Webinan In abstract class X implements YSie erklären, dass die Massenfunktionalität von X in einer abgeleiteten Klasse implementiert werden soll und dass sowohl die abstrakte als auch die abgeleitete Klasse in Y definierte Funktionen enthalten müssen , während class X implements Ynur impliziert wird, dass Klasse X in Y definierte Funktionen enthalten muss. Wenn Ihre Schnittstelle Y. soll nicht von einer anderen Klasse als XI implementiert werden, würde die Definition von Y als Schnittstelle überspringen und nur die Funktionen in Y als öffentliche / geschützte / private abstrakte Funktion implementieren, um sicherzustellen, dass sie in der abgeleiteten Klasse implementiert sind.
Calle Bergström

1
Schnittstellen können nicht nur die Definition von Methoden enthalten, sondern auch Konstanten
Thielicious

Hat Ihren Vergleich gefallen. Also wollte ich etwas hinzufügen. Schnittstellen können standardmäßig Klassenkonstanten haben, abstrakte Klassen nicht.
Noman Ibrahim

128

Warum abstrakte Klassen verwenden? Das Folgende ist ein einfaches Beispiel. Nehmen wir an, wir haben den folgenden Code:

<?php 

class Fruit {
    private $color;

    public function eat() {
        // chew
    }

    public function setColor($c) {
        $this->color = $c;
    }
}

class Apple extends Fruit {
    public function eat() {
        // chew until core
    }
}

class Orange extends Fruit {
    public function eat() {
        // peeling
        // chew
    }
}

Jetzt gebe ich dir einen Apfel und du isst ihn. Wie schmeckt es? Es schmeckt wie ein Apfel.

<?php 
$apple = new Apple();
$apple->eat();

// Now I give you a fruit.
$fruit = new Fruit();
$fruit->eat();

Wie schmeckt das? Nun, es macht nicht viel Sinn, also sollten Sie das nicht können. Dies wird erreicht, indem sowohl die Obstklasse als auch die darin enthaltene Essmethode abstrakt gemacht werden.

<?php 
abstract class Fruit {
    private $color;

    abstract public function eat(){}

    public function setColor($c) {
        $this->color = $c;
    }
}
?>

Eine abstrakte Klasse ist wie eine Schnittstelle, aber Sie können Methoden in einer abstrakten Klasse definieren, während sie in einer Schnittstelle alle abstrakt sind. Abstrakte Klassen können sowohl leere als auch arbeitende / konkrete Methoden haben. In Schnittstellen können dort definierte Funktionen keinen Körper haben. In abstrakten Klassen können sie.

Ein Beispiel aus der Praxis:

<?php 
abstract class person {

    public $LastName;
    public $FirstName;
    public $BirthDate;

    abstract protected function write_info();
}

final class employee extends person{

    public $EmployeeNumber;
    public $DateHired;

    public function write_info(){
        //sql codes here
        echo "Writing ". $this->LastName . "'s info to emloyee dbase table <br>";   
    }
}

final class student extends person{

    public $StudentNumber;
    public $CourseName;

    public function write_info(){
        //sql codes here
        echo "Writing ". $this->LastName . "'s info to student dbase table <br>";
    }
}

///----------
$personA = new employee;
$personB = new student;

$personA->FirstName="Joe";
$personA->LastName="Sbody";

$personB->FirstName="Ben";
$personB->LastName="Dover";

$personA->write_info();
// Writing Sbody's info to emloyee dbase table
$personB->write_info();
// Writing Dover's info to student dbase table 

2
Hallo, diese Antwort hat wahrscheinlich aufgrund der Art und Weise, wie sie formatiert ist, negative Stimmen erhalten. Es wäre gut, wenn es kein großer Codeblock wäre (vier Leerzeichen machen etwas zu einem Codeblock, ohne den Text zu entfernen, um ihn aus dem Block zu entfernen) und wenn dieser von irgendwoher kopiert wurde (es sieht so aus) es wäre höflich, sie gutzuschreiben.
Camilo Martin

9
Ich liebe dich für den Fruchtbeispielmann! Seit ich angefangen habe, PHP zu lernen, macht mir dieses Beispiel klar, vielen Dank
Raheel

23
+1 What does that taste like? Well, it doesn't make much sense, so you shouldn't be able to do that.Jetzt kenne ich abstrakt!
Webinan

Was macht das finalSchlüsselwort? Toller Beitrag, danke.
Gus

1
@VineeshKalarickal Was ich im Beispiel Person nicht verstehe, ist der Unterschied zwischen: 1) Verwenden der abstrakten Klasse Person (wie im Beispiel); 2) Schreiben von Person als Standardklasse und Überschreiben der Methode write_info () durch Mitarbeiter und Schüler.
Ferex

66

Es wird empfohlen, eine Schnittstelle zu verwenden, um den Vertrag und eine abstrakte Klasse als nur eine Implementierung davon anzugeben. Diese abstrakte Klasse kann einen Großteil des Boilerplates ausfüllen, sodass Sie eine Implementierung erstellen können, indem Sie einfach überschreiben, was Sie benötigen oder wollen, ohne eine bestimmte Implementierung verwenden zu müssen.


37

Nur um dies in die Mischung zu bringen, aber wie Cletus erwähnte, indem ich eine Schnittstelle in Verbindung mit einer abstrakten Klasse verwendete, benutze ich die Schnittstelle oft, um mein Design-Denken zu verdeutlichen.

Zum Beispiel:

<?php
class parser implements parserDecoratorPattern {
    //...
}

Auf diese Weise weiß jeder, der meinen Code liest (und weiß, was ein Dekorationsmuster ist), sofort a) wie ich meinen Parser erstelle und b) kann sehen, mit welchen Methoden das Dekorationsmuster implementiert wird.

Außerdem bin ich hier möglicherweise kein Java / C ++ / etc-Programmierer, aber hier können Datentypen ins Spiel kommen. Ihre Objekte sind von einem Typ, und wenn Sie sie weitergeben, ist der Typ programmatisch von Bedeutung. Wenn Sie Ihre kontrahierbaren Elemente in die Benutzeroberfläche verschieben, werden nur die von den Methoden zurückgegebenen Typen bestimmt, nicht jedoch der Basistyp der Klasse, die sie implementiert.

Es ist spät und ich kann mir kein besseres Psudo-Code-Beispiel vorstellen, aber hier ist:

<?php
interface TelevisionControls {};
class Remote implements TelevisionControls {};
class Spouse implements TelevisionControls {};
Spouse spouse = new Spouse();
Remote remote = new Remote();
isSameType = (bool)(remote == spouse)

1
Was für ein großartiges Beispiel! ;)
Joel Murphy

@ matt2000 Nicht sexistisch UND funktioniert jetzt auch für gleichgeschlechtliche Ehen. Großartige Bearbeitung. :)
Austen Hoogen

4
Dies ist ein großartiges Beispiel! Ich glaube jedoch nicht, dass Sie eine abstrakte Klasse instanziieren können, sondern eine Klasse, die sich von einer abstrakten Klasse erstreckt
Arielle Nguyen

2
würde nicht töten, damit der Sudo-Code zumindest wie die betreffende Sprache aussieht. jemand sollte ein paar Dollar da reinstecken.
Ich habe einmal mit einem Bären gerungen.

2
Obwohl das Beispiel lustig ist, können wir eine abstrakte Klasse nicht direkt instanziieren. Nehmen Sie bitte Änderungen am Beispiel vor, damit die Benutzer es möglicherweise nicht als gültige Verwendung in PHP betrachten.
saji89

16

Der Hauptunterschied besteht darin, dass eine abstrakte Klasse eine Standardimplementierung enthalten kann, eine Schnittstelle jedoch nicht.

Eine Schnittstelle ist ein Verhaltensvertrag ohne Implementierung.


16

Ich möchte hier nur hinzufügen, dass nur weil jede andere OO-Sprache eine Art von Schnittstellen und Abstraktion hat, dies nicht bedeutet, dass sie dieselbe Bedeutung und denselben Zweck haben wie in PHP. Die Verwendung von Abstraktion / Schnittstellen unterscheidet sich geringfügig, während Schnittstellen in PHP tatsächlich keine echte Funktion haben. Sie werden lediglich aus semantischen und schemabezogenen Gründen verwendet. Es geht darum, ein Projekt so flexibel wie möglich, erweiterbar und sicher für zukünftige Erweiterungen zu haben, unabhängig davon, ob der Entwickler später einen völlig anderen Nutzungsplan hat oder nicht.

Wenn Ihr Englisch nicht muttersprachlich ist, können Sie nachschlagen, was Abstraktion und Schnittstellen tatsächlich sind. Und suchen Sie auch nach Synonymen.

Und das könnte Ihnen als Metapher helfen:

SCHNITTSTELLE

Nehmen wir an, Sie backen eine neue Art Kuchen mit Erdbeeren und haben ein Rezept zusammengestellt, das die Zutaten und Schritte beschreibt. Nur Sie wissen, warum es so gut schmeckt und Ihre Gäste mögen es. Dann beschließen Sie, Ihr Rezept zu veröffentlichen, damit auch andere Leute diesen Kuchen probieren können.

Der Punkt hier ist

- um es richtig zu machen
- um vorsichtig zu sein
- um Dinge zu verhindern, die schlecht werden könnten (wie zu viel Erdbeeren oder so etwas)
- um es den Leuten, die es ausprobieren, leicht zu machen
- um Ihnen zu sagen, wie lange was zu tun ist (wie Rühren) )
- um zu sagen, welche Dinge Sie tun können, aber nicht müssen

Genau DAS beschreibt Schnittstellen. Es ist eine Anleitung, eine Reihe von Anweisungen, die den Inhalt des Rezepts beachten. Genauso, als würden Sie ein Projekt in PHP erstellen und den Code auf GitHub oder mit Ihren Freunden oder was auch immer bereitstellen. Eine Schnittstelle ist das, was Menschen tun können und was Sie nicht tun sollten. Regeln, die es halten - wenn Sie einer nicht gehorchen, wird das gesamte Konstrukt gebrochen.


ABSTRAKTION

Um mit dieser Metapher hier fortzufahren ... stellen Sie sich vor, Sie sind diesmal der Gast, der diesen Kuchen isst. Dann probieren Sie diesen Kuchen jetzt nach dem Rezept. Sie möchten jedoch neue Zutaten hinzufügen oder die im Rezept beschriebenen Schritte ändern / überspringen. Was kommt als nächstes? Planen Sie eine andere Version dieses Kuchens. Diesmal mit schwarzen Beeren und nicht mit Strohbeeren und mehr Vanillecreme ... lecker.

Dies ist, was Sie eine Erweiterung des ursprünglichen Kuchens betrachten könnten. Sie machen im Grunde eine Abstraktion davon, indem Sie ein neues Rezept erstellen, weil es ein bisschen anders ist. Es hat ein paar neue Schritte und andere Zutaten. Die Black Berry-Version enthält jedoch einige Teile, die Sie vom Original übernommen haben - dies sind die grundlegenden Schritte, die jede Art von Kuchen haben muss. Wie Zutaten wie Milch - das hat jede abgeleitete Klasse.

Jetzt möchten Sie Zutaten und Schritte austauschen und diese MÜSSEN in der neuen Version dieses Kuchens definiert werden. Dies sind abstrakte Methoden die für den neuen Kuchen definiert werden müssen, weil der Kuchen eine Frucht enthalten sollte, aber welche? Also nimmst du diesmal die schwarzen Beeren. Erledigt.

Los geht's, Sie haben den Kuchen erweitert, sind der Benutzeroberfläche gefolgt und haben Schritte und Zutaten daraus abstrahiert.


1
Dies war mein Lieblingsvergleich von allem, was mit PHP zu tun hat. Es machte wirklich Sinn. Vielen Dank!
cbloss793

13

Um einige der bereits ausgezeichneten Antworten zu ergänzen:

  • Mit abstrakten Klassen können Sie einen gewissen Grad an Implementierung bereitstellen. Schnittstellen sind reine Vorlagen. Eine Schnittstelle kann nur Funktionen definieren , sie kann sie niemals implementieren.

  • Jede Klasse, die die Schnittstelle implementiert, verpflichtet sich, alle von ihr definierten Methoden zu implementieren, oder sie muss als abstrakt deklariert werden.

  • Schnittstellen können dabei helfen, die Tatsache zu verwalten, dass PHP wie Java keine Mehrfachvererbung unterstützt. Eine PHP-Klasse kann nur einen einzelnen Elternteil erweitern. Sie können jedoch ein Klassenversprechen abgeben, so viele Schnittstellen zu implementieren, wie Sie möchten.

  • Typ: Für jede implementierte Schnittstelle nimmt die Klasse den entsprechenden Typ an. Da jede Klasse eine Schnittstelle (oder mehrere Schnittstellen) implementieren kann, verbinden Schnittstellen effektiv Typen, die ansonsten nicht miteinander zusammenhängen.

  • Eine Klasse kann sowohl eine Oberklasse erweitern als auch eine beliebige Anzahl von Schnittstellen implementieren:

    class SubClass extends ParentClass implements Interface1, Interface2 {
        // ...
    }

Bitte erläutern Sie, wann ich eine Schnittstelle verwenden soll und wann ich eine abstrakte Klasse verwenden soll.

Verwenden Sie eine Schnittstelle, wenn Sie nur eine Vorlage ohne Implementierung bereitstellen müssen, und Sie möchten sicherstellen, dass jede Klasse, die diese Schnittstelle implementiert, dieselben Methoden hat wie jede andere Klasse, die sie implementiert (zumindest).

Verwenden Sie eine abstrakte Klasse, wenn Sie eine Grundlage für andere Objekte erstellen möchten (eine teilweise erstellte Klasse). Die Klasse, die Ihre abstrakte Klasse erweitert, verwendet einige definierte / implementierte Eigenschaften oder Methoden:

<?php
// interface
class X implements Y { } // this is saying that "X" agrees to speak language "Y" with your code.

// abstract class
class X extends Y { } // this is saying that "X" is going to complete the partial class "Y".
?>

Wie kann ich meine abstrakte Klasse in eine Schnittstelle umwandeln?

Hier ist ein vereinfachter Fall / Beispiel. Nehmen Sie alle Implementierungsdetails heraus. Ändern Sie beispielsweise Ihre abstrakte Klasse von:

abstract class ClassToBuildUpon {
    public function doSomething() {
          echo 'Did something.';
    }
}

zu:

interface ClassToBuildUpon {
    public function doSomething();
}

12

Aus phylosophischer Sicht:

  • Eine abstrakte Klasse repräsentiert eine "ist eine" Beziehung. Nehmen wir an, ich habe Früchte. Nun, ich hätte eine abstrakte Fruchtklasse, die gemeinsame Verantwortlichkeiten und Verhaltensweisen teilt.

  • Eine Schnittstelle repräsentiert eine "sollte" -Beziehung. Eine Schnittstelle sollte meiner Meinung nach (was die Meinung eines Junior-Entwicklers ist) durch eine Aktion oder etwas in der Nähe einer Aktion benannt werden (Entschuldigung, ich kann das Wort nicht finden, ich bin kein englischer Muttersprachler). Sagen wir IEatable. Sie wissen, dass es gegessen werden kann, aber Sie wissen nicht, was Sie essen.

Aus codierender Sicht:

  • Wenn Ihre Objekte Code dupliziert haben, ist dies ein Hinweis darauf, dass sie ein allgemeines Verhalten aufweisen. Dies bedeutet, dass Sie möglicherweise eine abstrakte Klasse benötigen, um den Code wiederzuverwenden, was mit einer Schnittstelle nicht möglich ist.

  • Ein weiterer Unterschied besteht darin, dass ein Objekt so viele Schnittstellen implementieren kann, wie Sie benötigen. Aufgrund des "Diamantproblems" können Sie jedoch nur eine abstrakte Klasse haben (lesen Sie hier, um zu erfahren, warum! Http://en.wikipedia.org/wiki/ Mehrfachvererbung # The_diamond_problem )

Ich habe wahrscheinlich einige Punkte vergessen, aber ich hoffe, es kann die Dinge klären.

PS: Das "ist ein" / "sollte tun" wird von Vivek Vermanis Antwort gebracht, ich wollte seine Antwort nicht stehlen, nur um die Begriffe wiederzuverwenden, weil ich sie mochte!


2
Das Wort, das Sie suchen, ist essbar, glaube ich.
Travis Weston

1
Eigentlich glaube ich, dass es ein "Verb" ist, ein "Tun-Wort"
Grizly

7

Die technischen Unterschiede zwischen einer abstrakten Klasse und einer Schnittstelle sind in den anderen Antworten bereits genau aufgeführt. Ich möchte eine Erklärung hinzufügen, um zwischen einer Klasse und einer Schnittstelle zu wählen, während der Code für die objektorientierte Programmierung geschrieben wird.

Eine Klasse sollte eine Entität darstellen, während eine Schnittstelle das Verhalten darstellen sollte.

Nehmen wir ein Beispiel. Ein Computermonitor ist eine Entität und sollte als Klasse dargestellt werden.

class Monitor{
    private int monitorNo;
}

Es wurde entwickelt, um Ihnen eine Anzeigeschnittstelle bereitzustellen, daher sollte die Funktionalität durch eine Schnittstelle definiert werden.

interface Display{
    void display();
}

Es gibt viele andere Dinge zu beachten, wie in den anderen Antworten erläutert, aber dies ist die grundlegendste Sache, die die meisten Leute beim Codieren ignorieren.


2
PHP definiert keine Rückgabetypen und das OP hat diese Frage mitPHP
Purefan

1

Ich wollte nur ein Beispiel hinzufügen, wann Sie möglicherweise beide verwenden müssen. Ich schreibe derzeit einen Datei-Handler, der an ein Datenbankmodell in einer Allzweck-ERP-Lösung gebunden ist.

  • Ich habe mehrere abstrakte Klassen, die den Standard-Crud behandeln, sowie einige spezielle Funktionen wie Konvertierung und Streaming für verschiedene Kategorien von Dateien.
  • Die Dateizugriffsschnittstelle definiert eine Reihe allgemeiner Methoden, die zum Abrufen, Speichern und Löschen einer Datei erforderlich sind.

Auf diese Weise habe ich mehrere Vorlagen für verschiedene Dateien und einen gemeinsamen Satz von Schnittstellenmethoden mit klarer Unterscheidung. Die Schnittstelle bietet die richtige Analogie zu den Zugriffsmethoden und nicht zu einer abstrakten Basisklasse.

Wenn ich später Adapter für verschiedene Dateispeicherdienste erstellen werde, wird diese Implementierung es ermöglichen, die Schnittstelle an anderer Stelle in völlig unterschiedlichen Kontexten zu verwenden.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.