Mit Schnittstellen können Sie Code erstellen, der die Methoden der Klassen definiert, die ihn implementieren. Sie können diesen Methoden jedoch keinen Code hinzufügen.
Mit abstrakten Klassen können Sie dasselbe tun und der Methode Code hinzufügen.
Wenn Sie nun dasselbe Ziel mit abstrakten Klassen erreichen können, warum brauchen wir dann überhaupt das Konzept von Schnittstellen?
Mir wurde gesagt, dass es mit der OO-Theorie von C ++ bis Java zu tun hat, worauf PHPs OO-Zeug basiert. Ist das Konzept in Java nützlich, aber nicht in PHP? Ist es nur ein Weg, um zu verhindern, dass Platzhalter in der abstrakten Klasse verstreut sind? Vermisse ich etwas
Antworten:
Der gesamte Sinn von Schnittstellen besteht darin, Ihnen die Flexibilität zu geben, dass Ihre Klasse gezwungen wird, mehrere Schnittstellen zu implementieren, aber dennoch keine Mehrfachvererbung zulässt. Die Probleme beim Erben von mehreren Klassen sind vielfältig und die Wikipedia- Seite fasst sie ziemlich gut zusammen.
Schnittstellen sind ein Kompromiss. Die meisten Probleme mit der Mehrfachvererbung gelten nicht für abstrakte Basisklassen. Daher deaktivieren die meisten modernen Sprachen heutzutage die Mehrfachvererbung, rufen jedoch Schnittstellen für abstrakte Basisklassen auf und ermöglichen es einer Klasse, so viele dieser Klassen zu "implementieren", wie sie möchten.
quelle
Das Konzept ist in der objektorientierten Programmierung rundum nützlich. Für mich ist eine Schnittstelle ein Vertrag. Solange meine Klasse und Ihre Klasse sich auf diesen Methodensignaturvertrag einigen, können wir eine "Schnittstelle" herstellen. Was abstrakte Klassen betrifft, so sehe ich eher Basisklassen, die einige Methoden auslöschen, und ich muss die Details ausfüllen.
quelle
Warum brauchen Sie eine Schnittstelle, wenn es bereits abstrakte Klassen gibt? Um Mehrfachvererbung zu verhindern (kann mehrere bekannte Probleme verursachen).
Eines dieser Probleme:
Quelle: https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem
Warum / wann eine Schnittstelle verwenden? Ein Beispiel ... Alle Autos auf der Welt haben die gleiche Schnittstelle (Methoden) ...
AccelerationPedalIsOnTheRight()
,BrakePedalISOnTheLeft()
. Stellen Sie sich vor, jede Automarke hätte diese "Methoden" anders als eine andere Marke. BMW hätte die Bremsen auf der rechten Seite und Honda hätte die Bremsen auf der linken Seite des Rades. Die Leute müssten jedes Mal lernen, wie diese "Methoden" funktionieren, wenn sie eine andere Automarke kaufen. Aus diesem Grund ist es eine gute Idee, dieselbe Benutzeroberfläche an mehreren "Stellen" zu verwenden.Was macht eine Schnittstelle für Sie (warum sollte jemand überhaupt eine verwenden)? Eine Schnittstelle verhindert, dass Sie "Fehler" machen (sie stellt sicher, dass alle Klassen, die eine bestimmte Schnittstelle implementieren, über die Methoden verfügen, die sich in der Schnittstelle befinden).
Auf diese Weise wird die
Create()
Methode immer auf die gleiche Weise verwendet. Es spielt keine Rolle, ob wir dieMySqlPerson
Klasse oder dieMongoPerson
Klasse verwenden. Die Art und Weise, wie wir eine Methode verwenden, bleibt gleich (die Schnittstelle bleibt gleich).Zum Beispiel wird es so verwendet (überall in unserem Code):
Auf diese Weise kann so etwas nicht passieren:
Es ist viel einfacher, sich an eine Schnittstelle zu erinnern und überall dieselbe zu verwenden, als mehrere verschiedene.
Auf diese Weise kann das Innere der
Create()
Methode für verschiedene Klassen unterschiedlich sein, ohne den "äußeren" Code zu beeinflussen, der diese Methode aufruft. Der externe Code muss lediglich wissen, dass die MethodeCreate()
1 parameter ($personObject
) hat, da der externe Code die Methode auf diese Weise verwendet / aufruft. Dem externen Code ist es egal, was innerhalb der Methode passiert. es muss nur wissen, wie man es benutzt / nennt.Sie können dies auch ohne Schnittstelle tun, aber wenn Sie eine Schnittstelle verwenden, ist diese "sicherer" (weil Sie dadurch keine Fehler machen können). Die Schnittstelle stellt sicher, dass die Methode
Create()
in allen Klassen, die die Schnittstelle implementieren, dieselbe Signatur (dieselben Typen und dieselbe Anzahl von Parametern) hat. Auf diese Weise können Sie sicher sein, dass JEDE Klasse, die dieIPersonService
Schnittstelle implementiert , die MethodeCreate()
(in diesem Beispiel) hat und nur 1 Parameter ($personObject
) benötigt, um aufgerufen / verwendet zu werden.Eine Klasse, die eine Schnittstelle implementiert, muss alle Methoden implementieren, die die Schnittstelle ausführt / hat.
Ich hoffe, dass ich mich nicht zu oft wiederholt habe.
quelle
Der Unterschied zwischen der Verwendung einer Schnittstelle und einer abstrakten Klasse hat für mich mehr mit der Codeorganisation zu tun als mit der Durchsetzung durch die Sprache selbst. Ich verwende sie häufig, wenn ich Code für andere Entwickler vorbereite, damit sie innerhalb der beabsichtigten Entwurfsmuster bleiben. Schnittstellen sind eine Art "Design by Contract", bei dem Ihr Code sich bereit erklärt, auf einen vorgeschriebenen Satz von API-Aufrufen zu antworten, die möglicherweise von Code stammen, auf den Sie keinen Zugriff haben.
Während die Vererbung von abstrakten Klassen eine "ist eine" Beziehung ist, ist dies nicht immer das, was Sie wollen, und das Implementieren einer Schnittstelle ist eher eine "verhält sich wie eine" Beziehung. Dieser Unterschied kann in bestimmten Zusammenhängen sehr bedeutend sein.
Angenommen, Sie haben ein abstraktes Klassenkonto, von dem viele andere Klassen ausgehen (Kontotypen usw.). Es gibt bestimmte Methoden, die nur für diese Typgruppe gelten. Einige dieser Kontounterklassen implementieren jedoch Versionable, Listable oder Editable, sodass sie in Controller geworfen werden können, die diese APIs verwenden möchten. Dem Controller ist es egal, um welchen Objekttyp es sich handelt
Im Gegensatz dazu kann ich auch ein Objekt erstellen, das sich nicht von Account aus erstreckt, z. B. eine abstrakte Benutzerklasse, und dennoch Listable and Editable, aber nicht Versionable implementieren, was hier keinen Sinn ergibt.
Auf diese Weise sage ich, dass die FooUser-Unterklasse KEIN Konto ist, sondern sich wie ein bearbeitbares Objekt verhält. Ebenso erstreckt sich BarAccount von Account, ist jedoch keine Benutzerunterklasse, sondern implementiert Editable, Listable und auch Versionable.
Das Hinzufügen all dieser APIs für Editable, Listable und Versionable zu den abstrakten Klassen selbst wäre nicht nur unübersichtlich und hässlich, sondern würde entweder die allgemeinen Schnittstellen in Account und User duplizieren oder mein User-Objekt zwingen, Versionable zu implementieren, wahrscheinlich nur, um eine zu werfen Ausnahme.
quelle
Schnittstellen sind im Wesentlichen eine Blaupause für das, was Sie erstellen können. Sie definieren, welche Methoden eine Klasse haben muss , aber Sie können zusätzliche Methoden außerhalb dieser Einschränkungen erstellen.
Ich bin mir nicht sicher, was Sie damit meinen, dass Sie Methoden keinen Code hinzufügen können - weil Sie das können. Wenden Sie die Schnittstelle auf eine abstrakte Klasse oder die Klasse an, die sie erweitert?
Eine Methode in der Schnittstelle, die auf die abstrakte Klasse angewendet wird, muss in dieser abstrakten Klasse implementiert werden. Wenden Sie diese Schnittstelle jedoch auf die Erweiterungsklasse an, und die Methode muss nur in der Erweiterungsklasse implementiert werden. Ich könnte mich hier irren - ich benutze Schnittstellen nicht so oft, wie ich könnte / sollte.
Ich habe mir Schnittstellen immer als Muster für externe Entwickler oder als zusätzlichen Regelsatz vorgestellt, um sicherzustellen, dass die Dinge korrekt sind.
quelle
Sie werden Schnittstellen in PHP verwenden:
$object instanceof MyInterface
Car
Objekt ca jetztstart()
,stop()
(EngineInterface) odergoRight()
,goLeft()
(Steering - Schnittstelle)und andere Dinge, an die ich momentan nicht denken kann
Nummer 4 ist wahrscheinlich der offensichtlichste Anwendungsfall, den Sie nicht mit abstrakten Klassen behandeln können.
Vom Denken in Java:
quelle
Schnittstellen existieren nicht als Basis, auf der Klassen erweitert werden können, sondern als Karte der erforderlichen Funktionen.
Das folgende Beispiel zeigt die Verwendung einer Schnittstelle, in die eine abstrakte Klasse nicht passt:
Nehmen wir an, ich habe eine Kalenderanwendung, mit der Benutzer Kalenderdaten aus externen Quellen importieren können. Ich würde Klassen schreiben, um den Import jeder Art von Datenquelle (ical, rss, atom, json) zu handhaben. Jede dieser Klassen würde eine gemeinsame Schnittstelle implementieren, die sicherstellen würde, dass alle über die gemeinsamen öffentlichen Methoden verfügen, die meine Anwendung zum Abrufen der Daten benötigt.
Wenn ein Benutzer dann einen neuen Feed hinzufügt, kann ich den Typ des Feeds identifizieren und die für diesen Typ entwickelte Klasse zum Importieren der Daten verwenden. Jede Klasse, die zum Importieren von Daten für einen bestimmten Feed geschrieben wurde, hat einen völlig anderen Code. Andernfalls gibt es möglicherweise nur sehr wenige Ähnlichkeiten zwischen den Klassen, außer dass sie für die Implementierung der Schnittstelle erforderlich sind, über die meine Anwendung sie verwenden kann. Wenn ich eine abstrakte Klasse verwenden würde, könnte ich sehr leicht die Tatsache ignorieren, dass ich die getEvents () -Methode nicht überschrieben habe, die dann meine Anwendung in diesem Fall beschädigen würde, während die Verwendung einer Schnittstelle meine App nicht ausführen würde, wenn eine der Methoden vorhanden wäre In der Schnittstelle definierte sind in der Klasse, die sie implementiert hat, nicht vorhanden. Meine App muss sich nicht darum kümmern, welche Klasse sie verwendet, um Daten aus einem Feed abzurufen.
Um noch einen Schritt weiter zu gehen, erweist sich die Benutzeroberfläche als äußerst nützlich, wenn ich zu meiner Kalender-App zurückkehre, um einen weiteren Feed-Typ hinzuzufügen. Durch die Verwendung der ImportableFeed-Schnittstelle kann ich weitere Klassen hinzufügen, die verschiedene Feed-Typen importieren, indem ich einfach neue Klassen hinzufüge, die diese Schnittstelle implementieren. Auf diese Weise kann ich Tonnen von Funktionen hinzufügen, ohne meine Kernanwendung unnötig erweitern zu müssen, da meine Kernanwendung nur darauf angewiesen ist, dass die öffentlichen Methoden verfügbar sind, die für die Schnittstelle erforderlich sind, solange meine neuen Feed-Importklassen die ImportableFeed-Schnittstelle implementieren Ich weiß, ich kann es einfach fallen lassen und in Bewegung bleiben.
Dies ist nur ein sehr einfacher Anfang. Ich kann dann eine andere Schnittstelle erstellen, für deren Implementierung alle meine Kalenderklassen erforderlich sein können, die mehr Funktionen bietet, die für den von der Klasse behandelten Feed-Typ spezifisch sind. Ein weiteres gutes Beispiel wäre eine Methode zur Überprüfung des Futtertyps usw.
Dies geht über die Frage hinaus, aber da ich das obige Beispiel verwendet habe: Schnittstellen haben ihre eigenen Probleme, wenn sie auf diese Weise verwendet werden. Ich muss sicherstellen, dass die Ausgabe, die von den implementierten Methoden zurückgegeben wird, um mit der Schnittstelle übereinzustimmen, und um dies zu erreichen, verwende ich eine IDE, die PHPDoc-Blöcke liest und den Rückgabetyp als Typhinweis in einen PHPDoc-Block der Schnittstelle einfügt, der dann wird Übersetzen Sie in die konkrete Klasse, die es implementiert. Meine Klassen, die die Datenausgabe der Klassen verwenden, die diese Schnittstelle implementieren, wissen dann zumindest, dass sie ein in diesem Beispiel zurückgegebenes Array erwarten:
Es gibt nicht viel Raum, um abstrakte Klassen und Schnittstellen zu vergleichen. Schnittstellen sind einfach Karten, bei deren Implementierung die Klasse über eine Reihe öffentlicher Schnittstellen verfügen muss.
quelle
Schnittstellen dienen nicht nur dazu, sicherzustellen, dass Entwickler bestimmte Methoden implementieren. Die Idee ist, dass Sie diese Methoden verwenden können, da diese Klassen garantiert über bestimmte Methoden verfügen, auch wenn Sie den tatsächlichen Typ der Klasse nicht kennen. Beispiel:
In vielen Fällen ist es nicht sinnvoll, eine Basisklasse bereitzustellen, ob abstrakt oder nicht, da die Implementierungen stark variieren und außer einigen Methoden nichts gemeinsam haben.
Dynamisch typisierte Sprachen haben den Begriff "Ententypisierung", bei der Sie keine Schnittstellen benötigen. Es steht Ihnen frei anzunehmen, dass das Objekt die Methode hat, die Sie aufrufen. Dies umgeht das Problem in statisch typisierten Sprachen, in denen Ihr Objekt über eine Methode verfügt (in meinem Beispiel read ()), die Schnittstelle jedoch nicht implementiert.
quelle
Meiner Meinung nach sollten Schnittstellen nicht funktionalen abstrakten Klassen vorgezogen werden. Es würde mich nicht wundern, wenn es dort überhaupt einen Performance-Hit geben würde, da nur ein Objekt instanziiert wird, anstatt zwei zu analysieren und zu kombinieren (obwohl ich nicht sicher bin, ob ich mit dem Innenleben nicht vertraut bin von OOP PHP).
Es ist wahr, dass Schnittstellen weniger nützlich / sinnvoll sind als beispielsweise im Vergleich zu Java. Auf der anderen Seite wird PHP6 noch mehr Typhinweise einführen, einschließlich Typhinweise für Rückgabewerte. Dies sollte den PHP-Schnittstellen einen gewissen Mehrwert verleihen.
tl; dr: interfaces definiert eine Liste von Methoden, die befolgt werden müssen (think API), während eine abstrakte Klasse einige grundlegende / allgemeine Funktionen bietet, die die Unterklassen an bestimmte Anforderungen anpassen.
quelle
In PHP können Sie mehrere Schnittstellen anwenden, indem Sie sie durch ein Komma trennen (ich denke, ich finde das keine saubere Lösung).
Bei mehreren abstrakten Klassen können sich mehrere Abstracts gegenseitig erweitern (auch hier bin ich mir nicht ganz sicher, aber ich glaube, ich habe das schon einmal gesehen). Das einzige, was Sie nicht erweitern können, ist eine Abschlussklasse.
quelle
Schnittstellen geben Ihrem Code keine Leistungssteigerungen oder ähnliches, aber sie können einen großen Beitrag zur Wartung leisten. Es ist wahr, dass eine abstrakte Klasse (oder sogar eine nicht abstrakte Klasse) verwendet werden kann, um eine Schnittstelle zu Ihrem Code einzurichten, aber geeignete Schnittstellen (die Sie mit dem Schlüsselwort definieren und die nur Methodensignaturen enthalten) sind einfach einfacher zu verwenden sortieren und lesen.
Abgesehen davon neige ich dazu, bei der Entscheidung, ob eine Schnittstelle über eine Klasse verwendet werden soll oder nicht, Diskretion zu walten. Manchmal möchte ich Standardmethodenimplementierungen oder Variablen, die allen Unterklassen gemeinsam sind.
Natürlich ist der Punkt bei der Implementierung mehrerer Schnittstellen auch ein vernünftiger. Wenn Sie eine Klasse haben, die mehrere Schnittstellen implementiert, können Sie ein Objekt dieser Klasse als verschiedene Typen in derselben Anwendung verwenden.
Die Tatsache, dass es sich bei Ihrer Frage um PHP handelt, macht die Dinge jedoch etwas interessanter. Das Tippen auf Schnittstellen ist in PHP immer noch nicht unbedingt erforderlich, da Sie jeder Methode unabhängig von ihrem Typ so ziemlich alles zuführen können. Sie können Methodenparameter statisch eingeben, aber ein Teil davon ist fehlerhaft (String verursacht meines Erachtens Schluckauf). Kombinieren Sie dies mit der Tatsache, dass Sie die meisten anderen Referenzen nicht eingeben können und es nicht viel Wert ist, die statische Eingabe in PHP zu erzwingen ( zu diesem Zeitpunkt ). Und aus diesem Grund ist der Wert von Schnittstellen in PHP , an diesem Punktist weit weniger als in stärker typisierten Sprachen. Sie haben den Vorteil der Lesbarkeit, aber sonst wenig. Die Mehrfachimplementierung ist nicht einmal vorteilhaft, da Sie die Methoden noch deklarieren und ihnen im Implementierer Text geben müssen.
quelle
Nachfolgend finden Sie die Punkte für die PHP-Schnittstelle
Beispielcode:
quelle
Wir haben gesehen, dass abstrakte Klassen und Schnittstellen insofern ähnlich sind, als sie abstrakte Methoden bereitstellen, die in den untergeordneten Klassen implementiert werden müssen. Sie weisen jedoch noch folgende Unterschiede auf:
Hoffe, dieser Wille hilft jedem zu verstehen!
quelle
Schnittstellen sind wie Ihre Gene.
Abstrakte Klassen sind wie deine eigentlichen Eltern.
Ihre Zwecke sind erblich bedingt, aber im Fall von abstrakten Klassen gegenüber Schnittstellen ist das, was vererbt wird, spezifischer.
quelle
Ich weiß nichts über andere Sprachen, was ist das Konzept der Schnittstelle dort. Aber für PHP werde ich mein Bestes geben, um es zu erklären. Seien Sie einfach geduldig und kommentieren Sie bitte, ob dies geholfen hat.
Die Regel
Nehmen wir nun ein Beispiel. Angenommen, wir haben zwei Spielzeuge: eines ist ein Hund und das andere ist eine Katze.
Wie wir wissen, bellt ein Hund und miaut eine Katze. Diese beiden haben dieselbe Sprechmethode, aber unterschiedliche Funktionen oder Implementierungen. Angenommen, wir geben dem Benutzer eine Fernbedienung mit einer Sprechtaste.
Dies ist ein guter Fall, um eine Schnittstelle zu verwenden, keine abstrakte Klasse, da die Implementierungen unterschiedlich sind. Warum? Merken
Wenn Sie die untergeordneten Klassen durch Hinzufügen einer nicht abstrakten Methode unterstützen müssen, sollten Sie abstrakte Klassen verwenden. Andernfalls würden Sie Schnittstellen wählen.
quelle