Neulich kam mir die Frage entgegen: „Erklär mal, was sind die Unterschiede zwischen Interfaces und abstrakten Klassen?“
Zunächst war ich irritiert und am Ende nicht ganz zufrieden mit meiner Erklärung. Gleichzeitig wurde mir bewusst, dass es oft Unklarheiten darüber gibt, warum und wann man Interfaces einsetzen sollte.
Also ein neuer Versuch, den Unterschied einfach zu erklären.
Worum geht es eigentlich?
Bevor wir tiefer eintauchen, sollten wir die Begriffe Interfaces und abstrakte Klassen in einen passenden Rahmen setzen.
In der Softwareentwicklung sprechen wir oft über Vertrauen und Verhalten:
- Vertrauen bedeutet, dass wir uns darauf verlassen können, dass ein bestimmter Code auf eine definierte Weise funktioniert.
- Verhalten beschreibt, wie sich eine Komponente verhält.
Ein Weg, um Vertrauen innerhalb einer Applikation zu schaffen, ist die Definition von Interfaces. Sie geben einen klaren Rahmen vor, den Klassen einhalten.
Auf der anderen Seite möchten wir in der Entwicklung oft Code-Duplikationen vermeiden. Ein Ansatz ist die Vererbung. Abstrakte Klassen sind ein Konzept aus der Vererbung.
Der Unterschied auf den Punkt gebracht
- Ein Interface ist ein Rahmen einer Sache. Es legt fest, welche Methoden eine Klasse haben muss, enthält aber keine konkrete Implementierung.
interface Logger {
public function log(string $message): void;
public function formatMessage(string $message): string;
}
class FileLogger implements Logger {
public function log(string $message): void {
file_put_contents('log.txt', $this->formatMessage($message), FILE_APPEND);
}
public function formatMessage(string $message): string
{
return sprintf("[%s] %s \n", (new DateTimeImmutable())->format('Y-m-d H:i:s'), $message);
}
}
class DatabaseLogger implements Logger {
public function log(string $message): void {
// persist stuff
}
public function formatMessage(string $message): string
{
return $message;
}
}
- Eine abstrakte Klasse ist eine Vorlage für eine Sache. Sie kann sowohl fertige Methoden (mit Logik) als auch abstrakte Methoden enthalten, die in Unterklassen implementiert werden müssen. Sie existiert nicht wirklich.
abstract class Logger {
abstract public function log(string $message): void;
public function formatMessage(string $message): string
{
return sprintf("[%s] %s \n", (new DateTimeImmutable())->format('Y-m-d H:i:s'), $message);
}
}
class FileLogger extends Logger {
public function log(string $message): void {
file_put_contents('log.txt', $this->formatMessage($message), FILE_APPEND);
}
}
class DatabaseLogger extends Logger {
public function log(string $message): void {
// persist stuff
}
}
- Eine konkrete Klasse ist die eigentliche Umsetzung der Sache. Sie kann ein Interface implementieren oder/und von einer abstrakten Klasse erben.
Kritik an abstrakten Klassen
Ein Nachteil abstrakter Klassen – zumindest in Sprachen, in denen eine Klasse nur genau eine andere Klasse erben kann (wie z. B. PHP) – ist, dass man schnell an strukturelle Herausforderungen stößt, wenn man Verhalten von mehreren abstrakten Klassen nutzen möchte.
Eine Alternative zur Wiederverwendung von Verhalten sind in Sprachen, wie Rust oder PHP, Traits.
Ein kleiner PHP-Reminder
Traits ermöglichen es, Verhalten in mehreren Klassen wiederzuverwenden. Doch wenn man Traits ohne ein Interface nutzt, geht das Vertrauen verloren.
Man könnte jetzt fragen, warum geht das Vertrauen verloren?
Naja, Traits in PHP können beliebige Methoden enthalten, ohne dass sie explizit durch eine Schnittstelle vorgegeben sind. Dadurch weiß man nicht sicher, welche Methoden vorhanden sein müssen. Ein Interface gibt eine feste Struktur vor, die sicherstellt, dass bestimmte Methoden existieren.
Deshalb ergibt sich eine klare Empfehlung:
👉 Wenn ihr schon Vererbung nutzt, dann kombiniert Traits mit Interfaces für eure Klassen!
Fazit
Interfaces und abstrakte Klassen sind unterschiedliche Dinge:
- Interfaces helfen dabei, Vertrauen und Konsistenz im Code sicherzustellen.
- Abstrakte Klassen ermöglichen es, gemeinsame Logik bereitzustellen, um Code-Duplikation zu vermeiden.
Beide Konzepte haben ihren Platz – und es kommt auf den Kontext an, wann abstrakte Klassen sinnvoll sind.
Schreibe einen Kommentar