Kolumne: Quality Time

Von Zwängen und Nöten: Interface Segregation Principle
Kommentare

In der aktuellen Serie über die SOLID-Prinzipien [1] nach Robert C. Martin ist in dieser Ausgabe das I dran. Haben Sie die ersten drei Teile der Serie zu diesen wichtigen Regeln des objektorientierten Softwaredesigns verpasst? Kein Problem, wir halten die Artikel unter [2], [3] und [4] zum Nachlesen für Sie bereit.

PHP Magazin

Die Kolumne „Von Zwängen und Nöten“ von Tobias Schlitt ist erstmalig erschienen im PHP Magazin 1.2013

Hinter dem I versteckt sich das so genannte „Interface Segregation Principle“. In der Objektorientierung werden Interfaces landläufig dazu benutzt, Verwendungsmöglichkeiten von oft sehr unterschiedlichen Klassen zu beschreiben. So sind Cachable und Serializable klassische Beispiele für Interfaces, die von völlig verschiedenen Klassen implementiert werden können, beispielsweise von den Datenobjekten User und Product. Ein Interface beschreibt also eine einzelne spezifische Verantwortlichkeit einer Klasse.

Ich kann Ihren Aufschrei vor dem Magazin im Moment des Schreibens beinahe hören, denn: Sagt nicht das „Single Responsibility Principle“ (das S in SOLID), dass jede Klasse nur eine einzelne Verantwortlichkeit tragen soll? Richtig, die Granularität, mit der Verantwortlichkeiten betrachtet und definiert werden, kann jedoch stark variieren. So kapselt ein User-Modell als Hauptaspekt Daten und Logik eines Benutzers. Soll ein User aber gecacht werden, zählt nur die wesentlich feinere Eigenschaft, dass das User-Modell gecacht werden kann.

Genau hier setzt das Interface Segregation Principle an, das sinngemäß sagt: Kein Codemodul sollte gezwungen werden, mehr Funktionalität entgegenzunehmen als eigentlich benötigt wird. So macht es für den Cache keinen Unterschied, ob er einen User oder ein Product cachen soll, solange die Voraussetzungen für die Cachbarkeit erfüllt sind.
Aber lassen Sie mich ein konkretes Beispiel zur Veranschaulichung vorstellen. Der folgende Codeschnipsel zeigt den Ausschnitt einer Klasse, die Zugriffe auf ein Google-API bereitstellt:

class GoogleApi
{
  // ... 
  public function getWeatherForLocation( Location $location )
    { /* ... */ }
  public function getNewsForCountry( Country $country, $limit = 10 )
    { /* ... */ }
}

Da in einem Projekt unterschiedliche Daten von Google abgefragt werden müssen, enthält die Klasse gänzlich verschiedene Methoden, die alle zu ihrer Hauptverantwortlichkeit zählen: Zugriff auf das Google-API bereitzustellen. Ist es allerdings sinnvoll, jeder Codestelle, die bestimmte Daten aus dem API benötigt, die gesamte GoogleApi-Klasse zur Verfügung zu stellen? Nein, sicherlich nicht – dem WeatherWidgetController die Möglichkeit einzuräumen, News von Google abzufragen, ergibt keinen Sinn. Und das aus mehreren Gründen: Zum einen ist es so schwieriger, später einzelne Aspekte – wie das Laden von Wetterdaten – durch andere APIs erledigen zu lassen. Denn im Kontext der Verwendung des Google-API ist dies nur ein einzelner Aspekt. Zum zweiten bürdet man dem Implementor des WeatherWidgetController auf, sich potenziell durch alle Methoden des API zu wühlen, bevor er die passende gefunden hat. Und letztlich eröffnet man unerfahrenen Entwicklern Tür und Tor, jede andere Methode der GoogleApi-Klasse zu verwenden; auch wenn es beispielsweise in diesem Fall gar keinen Sinn ergibt, News zu laden oder Schlimmeres. Es ist also eine gute Idee, die entstehende Abhängigkeit auf den benötigten Kontext einzugrenzen, indem man ein Interface einführt:

class GoogleApi implements WeatherLoader
{
  // .
}

So kann der WeatherWidgetController nur eine Abhängigkeit auf den WeatherLoader erhalten, was die oben aufgezählten Probleme behebt.

Natürlich hätte es, wie so oft, auch andere Möglichkeiten gegeben, dies zu erreichen. Beispielsweise durch eine WeatherLoader-Komponente auf einer höheren Architekturschicht, die lediglich die GoogleAPI-Komponente als Backend verwendet und nach oben hin nur die passende Rollen-Funktionalität bereitstellt. Interfaces und ihre Einsatzzwecke sind also ein hervorragendes Diskussionsthema. Eine Grundregel möchte ich Ihnen aber zum Abschluss ans Herz legen, und sie lautet, Interfaces immer vom Standpunkt des Benutzers aus zu entwerfen und auf gar keinen Fall „schon mal ein paar Interfaces anzulegen“.

Tobias Schlitt ist Diplominformatiker (Uni) und arbeitet seit 1999 in professionellen Webprojekten auf Basis von PHP. Als Open-Source-Enthusiast beteiligt er sich an verschiedenen Communityprojekten. Tobias ist Mitgründer der Qafoo GmbH (http://qafoo.com), die Entwicklungsteams dabei unterstützt, hochqualitative Websoftware zu entwickeln. Dazu zählen unter anderem Consulting und Training zu Qualitätssicherungsprozessen und professionellem Software-Engineering.
Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -