Facebook
Twitter
Google+
Kommentare
16
Willkommen bei "the web hates me". Mittlerweile hat unser Team ein tolles neues Monitoringtool für Agenturen gelauncht. Unter dem Namen koality.io haben wir einen Service geschaffen, der er Agenturen ermöglicht mit sehr geringen Kosten alle Ihre Webseiten zu überwachen.

Abstrakte Klassen vs. Interfaces – 0:1

Heute wollen wir mal einen kleinen Wettstreit zwischen abstrakten Klassen und Interfaces starten. Vielleicht mache ich ja eine Reihe draus. Mal schauen wie es ankommt. Da es in der PHP Gemeinde leider nicht sehr verbreitet ist Interfaces einzusetzen, möchte ich doch mal eine Lanze brechen und mal einen Vorteil der Interfaces gegenüber anderer Objekt­orientierter Konstrukte aufzeigen.

Ich kann mich noch an eine Diskussion an einen Ex-Arbeitskollegen erinnern, der meinte, dass abstrakte Klassen alles hergeben, was ich mit Interfaces machen kann. Sie wären sozusagen unnötig. Ich hoffe, dass er dies liest und morgen anderer Meinung ist. Naja vielmehr hoffe ich, dass ich mein Argument so gut formulieren kann, dass er es kapiert.

Also fangen wir an. Interfaces sind dazu da das Verhalten einer Klasse nach außen festzulegen. Wenn ich das Interface kenne, gegen das eine Klasse programmiert wurde, so muss mich nicht interessieren, wie es umgesetzt wurde. Ich kann es einfach verwenden. Und das tolle daran ist:  jede Klasse, die dieses Interface implementiert kann einfach durch eine andere ausgetauscht werden. Super Sache. Aber die Verfechter von abstrakten Klassen werden jetzt sagen: „Moment mal, das kann ich auch!“. Was macht man in einem solchen Fall? Beispiele zeigen.

interface Countable
{
  public function count( );
}

abstract class Countable
{
  abstract public function count( );
}

Tja dumm gelaufen. Diese zwei Varianten sind wirklich gleich mächtig. Beide zwingen einen dazu die Funktion count zu implementieren und beide können beim Typehinting verwendet werden. Ich würde mal sagen, es steht also immer noch 0:0 in unserem kleinen Wettstreit. Was machen wir jetzt aber wenn wir noch ein „Interface“ haben. Nehmen wir ein Sortable Interface.

interface Sortable
{
  public function sort( );
}

abstract class Sortable
{
  abstract public function sort( );
}

Und wieder ist es genau das gleiche. War ja auch zu erwarten, ich habe ja einfach nur die Namen ausgetauscht. Jetzt will ich aber eine Klasse haben, die sowohl Countable als auch Sortable ist. Tooooor. 0:1 für das Interface. Interfaces haben die wunderbare Eigenschaft, dass hier „Mehrfachvererbung“ geht, was bei Klassen nicht funktioniert. Was auch gut ist, denn bei Klassen bekommt man leicht Probleme dabei (siehe Diamantenproblem).  Ich kann also ohne Probleme beide Interfaces implementieren. Sobold ich mich aber für eine Superklasse (Elternklasse) entschieden habe, habe ich mir den kompletten Abteilungsbaum zugemacht.

Wenn es unbedingt nötig sein sollte, kann man ja getrost trotzdem von der abstrakten Klassen ableiten. Das natürlich nur, wenn dort schon Funktionalitäten verortet sind, die man benötigt. Abstrakte Klassen haben aber auch ihr Einsatzgebiet, dass ich euch aber ein ander mal verraten werde. Ich habe ja schließlich noch eine Menge von Artikel vor mir.

Eine Sache möchte ich euch noch mitgeben: Benutzt Interfaces!!! Die Dinger sind so schön und nützlich.

Über den Autor

Nils Langner

Nils Langner ist der Gründer von "the web hates me" und auch der Hauptautor. Im wahren Leben leitet er das Qualitätsmanagementteam im Gruner+Jahr-Digitalbereich und ist somit für Seiten wie stern.de, eltern.de und gala.de aus Qualitätssicht verantwortlich. Nils schreibt seit den Anfängen von phphatesme, welches er ebenfalls gegründet hat, nicht nur für diverse Blogs, sondern auch für Fachmagazine, wie das PHP Magazin, die t3n, die c't oder die iX. Nebenbei ist er noch ein gern gesehener Sprecher auf Konferenzen. Herr Langner schreibt die Texte über sich gerne in der dritten Form.
Kommentare

16 Comments

  1. Wer statt Interfaces abstrakte Klassen verwendet verliert die Möglichkeit beides zu kombinieren.

    interface iObservable
    	{
    	public function registerObserver($params);
    	}
    abstract class Observable implements iObservable
    	{
    	private $observers = array();
    	public function registerObserver($params){}
    	}
    interface iMail
    	{
    	public function setSubject($subject);
    	public function setBody($body);
    	}
    abstract class Mail extends Observable implements iMail 
    	{
    	private $subject = "";
    	private $body = "";
    	public function setSubject($subject){$this->subject = $subject;}
    	public function setBody($body){$this->body = $body;}
    	abstract public function send();
    	}
    class MailSmtp extends Mail 
    	{
    	public function send(){}
    	}
    class MailSendmail extends Mail 
    	{
    	public function send(){}
    	}
    
    Reply
  2. Wir haben Interfaces und Abstrakte Klassen in der Schule ein wenig angeschaut, jedoch nicht so sehr vertieft…

    Sehe ich das jetzt richtig:
    Ein Interface kann von einem Interface ableiten. Eine Abstrakte Klasse kann jedoch nicht von einer Abstrakten Klasse abgeleitet werden?

    Reply
  3. @rniederer: Ne das stimmt nicht 🙂 Ich kann gegen MEHRERE Interfaces prorammieren aber maximal von EINER Klasse ableiten.

    Natürlich könnte ich in meinem Beispiel beide abstrakte Klassen hintereinander Ableiten, aber was machst du, wenn du nur eine Schnittstelle implementieren willst? Das wird dann nicht gehen.

    Reply
  4. Und ganz wichtig: Zwischen von einander abgeleiteten Klassen beseht eine „ist-ein“ Beziehung also um mit dem klassischen Beispiel class Auto extends Fahrzeug {} – ein Auto ist ein Fahrzeug und hat alle Eigenschaften eines Fahrzeuges und kann alles was ein Fahrzeug kann. Das interface sagt nur, dass das implementierende ene Fähigkeit hat.

    Entscheiden be abstrakten Klassen ist auch: Die kann gewisse Funktionalität implementieren, das Interface beschreibt wirklich nur die Schnittstelle.

    Reply
  5. @Nils:
    Danke…

    @Johannes:
    Danke, das weiss ich… ein bisschen hab ich in der Schule auch aufgepasst resp. ein bisschen wurde uns auch was beigebracht 😉
    Mir war nur das mit der Vererbung resp. Ableitung nicht ganz klar 😀

    Reply
  6. Ein 1:1 oder sogar 2:1 (wenn dein Artikel zu 1:1 geschrieben ist) dürfte aber die Implementierung von Attributen bei abstrakten Klassen liefern 🙂 (was in Interfaces nicht möglich ist)

    Reply
  7. Moin Gemeinde,

    Joe –
    hats voll getroffen. So ähnlich siehts bei mir auch meistens aus.
    Eine abstrakte Klasse, die 90% der Standardfunktionalität implementiert, und ein passendes Interface dazu, das die
    benutzenden Klassen von genau dieser Implementierung löst.

    Das gibt dem Entwickler die Möglichkeiten, die Standardmethoden (geerbt von der abstrakten Klasse) anzupassen, oder eine komplett eigenständige Implementierung – eventuell sogar mit einer neuen abstrakten Klasse – drüberzubügeln.

    Johannes –
    hat genau die Denkweise erkannt, die ich (leider) immer wieder -und gehäuft bei Sprachen die OOP erst im Nachhinein bekamen (PHP/VB/Delpi/Perl…) – antreffe.

    Es gab halt irgendwann mal ein Tutorial über Klassen und eine Beispielimplementierung (MySQL oder Mail oder http://FTP...), die genau diese eine Möglichkeit der Vererbung nutzt.
    Als Fazit bleibt dem Neuling das Gefühl, jetzt endlich auch mal dass Schlüsselwort „class“ benutzt zu haben und somit ein OO-Design zu haben.
    Ich nenne das PWO (Programming-With-Objects), anstatt OOP, da die Objekte im Endeffekt nur als erweiterte includes benutzt werden.

    mfg
    straffi

    denic-ergebnis diese posts:
    – Die Domain „drueberzubuegeln.de“ ist nicht registriert
    – Die Domain „programming-with-objects.de“ ist nicht registriert.

    Reply
  8. Nun, ich bin programmiere nun noch nicht sooo lange Objekt orientiert und in der Schule kann uns der Lehrer keine genauen Beisipiele geben…

    -> Kann mir jemand ein Beispiel aufzeigen, bei dem man abstrakte Klassen oder Interfaces braucht…

    Reply
  9. Hallo Nils,

    Du schreibst:

    „Interfaces haben die wunderbare Eigenschaft, dass hier “Mehrfachvererbung” geht, was bei Klassen nicht funktioniert.“

    Ich finde, „Mehrfachvererbung“ ist hier die so ziemlich unpassendste Formulierung. #7 und #11 treffen’s wohl am Besten:

    Erbt man von einer abstrakten Klasse, so hat die erbende Klasse (erstmal) automatisch alle Eigenschaften der abstrakten Klasse. Die Eigenschaften und Fähigkeiten können unter Umständen nicht einmal überschrieben werden.

    Ein Interface hingegen gibt tatsächlich lediglich vor, dass eine implementierende Klasse die im Interface definierten Eigenschaften und Fähigkeiten besitzen muss. Hier sehe ich insbesondere bei großen Projekten einen weiteren Nutzen:

    Wenn ich (als Entwickler) Klassen eines Moduls eines Anderen verwenden will/muss, schaue ich mir lediglich die Dokumentationen seiner Interfaces an. Wie seine konkreten Klassen, die ich letztendlich benutze, funktionieren, braucht mich nicht zu interessieren.

    Reply
  10. Hallo Nils und Thomas,
    ich finde der Einwand von Thomas richtig. Prinzipiell sind Schnittstellen in weitere Sinne Verträge zur Benutzung von Modulen, Bibliotheken … etc. Solche Schnittstellen gewährleisten die Unabhängigkeit der Software von der Umgebung, bestehen vorwiegend aus Spezifikationen und können auf viele verschiedene weisen implementiert werden (selbst ohne interfaces in den Sprachen, die nicht darüber verfügen). Nun manche Sprachen bieten das Konstrukt der interface, mit dem man solche Benutzungsverträge gut implementieren kann.

    Den Ergebnis hat Thomas bereits sehr schön ausgedruckt:

    „Wenn ich (als Entwickler) Klassen eines Moduls eines Anderen verwenden will/muss, schaue ich mir lediglich die Dokumentationen seiner Interfaces an. Wie seine konkreten Klassen, die ich letztendlich benutze, funktionieren, braucht mich nicht zu interessieren.“

    Reply
  11. Halli Hallo,
    bin gerade durch Zufall drüber gestolpert.
    Danke für den Artikel. Ich muß mich dem Thomas anschließen, auch auf die Gefahr hinaus ein Haar zu spalten: Interfaces werden implementiert und nicht vererbt.

    Ich würde Jederzeit ein Interface einer abstrakten Klasse vorziehen, solange in der Klasse nur Methoden ohne Implementierung vorgesehen sind. Sobald es aber an Felder und vollständig implementierte Methoden geht, warum nicht die abstrakte Klasse verwenden? Sie hat durchaus ihren Anwendungsfall und diese Linie zu ziehen: wann verwende ich was ist das eigentlich Interessante.

    Reply

Leave a Comment.

Link erfolgreich vorgeschlagen.

Vielen Dank, dass du einen Link vorgeschlagen hast. Wir werden ihn sobald wie möglich prüfen. Schließen