Die falsche und die richtige Methode, wie du Interfaces verwenden kannst.

Veröffentlicht: vor 5 monaten · Lesedauer ca. 9 Minuten

Bevor wir anfangen, möchte ich ganz kurz erwähnen, was ein Interface überhaupt ist.

Gibst du das Wort bei Duden ein, kommt prompt die Antwort:

Spezielle Schaltung zur elektronischen Anpassung zweier sonst inkompatibler Geräte oder Geräteteile

Sagen wir mal so, es ist nicht falsch, was da steht. Es ist aber nicht so 100%ig richtig 🙂

Als Zweites steht da „Schnittstelle„. Das ist wiederum goldrichtig. Hierfür wird jedoch als Beschreibung folgendes angegeben:

Verbindungsstelle zwischen Funktionseinheiten eines Datenverarbeitungs- oder -übertragungssystems, an der der Austausch von Daten oder Steuersignalen erfolgt

Also entweder bin ich zu blöde um hier den Zusammenhang zu erkennen oder dieser Satz ergibt genauso viel Sinn wie der obere.

Ok, Duden, jetzt probiere ich es mal:

Definiert einen Mindestsatz an Berührungspunkten zwischen zwei verschiedenen Systemen.

Na gut. Ich gebe es ja zu, es ist nicht so einfach „interface“ mit einem Satz zu erklären und dabei noch allgemein zu bleiben.

Jedoch bin ich nicht für das allgemeine bekannt, sondern versuche alles so einfach und konkret wie nur möglich darzustellen 🙂

Was ist ein Interface?

Eigentlich ist es ganz einfach.

Stell dir mal vor, du möchtest deine Haustiere füttern. Du hast einen Hund und eine Katze. Und wenn nicht, auch nicht schlimm 🙂

Wenn du das jetzt in Quellcode Ausdrücken würdest, könnte das so aussehen:

public void FeedDog(Dog dog)
{
	Tin tin = fridge.GetTin();
	tin.Open();
	tin.PutContentInto(dog.Bowl);
	tin.Dispose();
	
	WhistleTo(dog);
}

public void FeedCat(Cat cat)
{
	Tin tin = fridge.GetTin();
	tin.Open();
	tin.PutContentInto(cat.Bowl);
	tin.Dispose();
	
	CallThe(cat);
}

Und was stellen wir fest?

Genau, ist genau dasselbe. Und wenn du noch ein paar mehr Haustiere hast, muss das noch einmal kopiert werden.

Man wird hierdurch also extremst eingeschränkt und neigt zu wiederholungen.

Besser ist es doch sowas hier zu haben:

public interface Pet 
{
	Bowl Bowl { get; set; }
}

public void Feed(Pet pet)
{
	Tin tin = fridge.GetTin();
	tin.Open();
	tin.PutContentInto(pet.Bowl);
	tin.Dispose();
	
	Call(pet);
}

Damit haben wir schon mal viele Möglichkeiten abgedeckt.

Viele? Warum nur „viele“ und nicht alle?

Nun ja, ganz einfach: So ein Goldfisch hat nun einmal kein Futternapf 🙂

Und großen „Haustieren“, wie z.B. Pferden, Kühen, etc. haben auch kein Napf. Höchstens ein Trog. Und da wird auch kein Kühlschrank aufgemacht um eine Dose rauszuholen.

Also müssen wir noch einmal unterscheiden:

class Dog : InhousePetWithBowl { }
class Goldfish : UnterwaterPet { }
class Horse : BarnPet { }

Auf diese Art und Weise, können die Tierchen alle was zu essen bekommen:

me.Feed(doggy);
me.Feed(guppy);
me.Feed(blacky);

Wann sollte man ein Interface verwenden?

Grundsätzlich gilt immer:

So abstrakt wie möglich, so konkret wie nötig.

Und das gilt sowohl für die Erstellung als auch für die Verwendung.

Ein Interface sollte auch nicht komplett überladen sein.

Ich sehe immer wieder Interfaces, mit Methodendefinitionen im Guten zweistelligen Bereich. Wer soll die den bitte alle implementieren? Selbst Microsoft macht das in dem dotNET Framework.

Interfaces sollen klein gehalten werden.

Solche Interfaces sind schon bei der Erstellung zum Scheitern verurteilt und werden nur im äußersten Notfall eingebunden.

Das dotNET Framework bietet bereits einige Interfaces, die man verwenden kann.

Hat man sich zwei Hunde besorgt, kann man das Beispielsweise so schreiben.

class Person
{
	List<Dog> Dogs { get; set; }
}

Besser ist es jedoch, wenn man das abstrahiert und wie folgt schreibt:

class Person
{
	IEnumerable<IPet> Pets { get; set; }
}

Was haben wir daraus gewonnen?

  1. Unsere Liste kann jetzt neben Hunden auch Katzen, Hamster und auch Goldfische beinhalten.
  2. Wir sind nicht mehr auf eine Liste beschränkt. Es kann auch ein Array sein.

Auch Properties und Methodenparameter als Interface definieren.

Wann kann man sich ein Interface sparen?

public interface IService { }
public interface IAccountingService : IService { }
public class AccountingService : IAccountingService { }

Ist das ein guter oder ein schlechter Code?

Blöde Frage, natürlich schlecht. Steht ja unter der no-go Überschrift!“ 🙂

Erstelle kein Interface, nur um eins zu haben!

So cool die auch sind, aber in dem oberen Beispiel kann man sich die Interfaces tatsächlich sparen. Allerhöchstens noch das sogenannte „Marker-Interface“ erstellen.

Solange man nicht zwei komplett unterschiedliche Implementierungen der Buchhaltung hat, kann man sich das komplette Interface sparen.

public static void Main() 
{
	AccountingService accounting = new AccountingService();
	IPaymentService payment = new PayPalService();
	IDistributorService distrobutor = new EbayDistributorService();
	
	PayEngine engine = new PayEngine(accounting, payment, distrobutor)
}

class PayEngine
{
	public PayEngine(AccountingService accounting, IPaymentService payment, IDistributorService distrobutor)
	{
		accounting.Pay(distrobutor, payment);
	}
}

Und hier ist tatsächlich das Fingerspitzengefühl gefragt. Möchte man alles einheitlich haben und für jeden der Services ein Interface erstellen? Oder möchte man minimalistisch sein? Leider kann ich dir hier keine konkrete Antwort darauf geben.

Was du jedoch unbedingt vermeiden solltest:

Erstelle keine konkreten Interfaces!

Was meint den der Sergej den schon wieder damit?

Damit meine ich Interfaces oder auch abstrakte Klassen, die einfach nur 1 zu 1 Abbildungen von den konkreten Implementierungen sind. Also sowas wie: IPayPalService.

Sowas braucht kein Mensch!

Interfaces vs. Abstrakte Klassen

Im Grunde genommen sind reine abstrakte Klassen, nichts anderes als Interfaces. Doch, ein Unterschied haben abstrakte Klassen:

Es ist mehr Quellcode nötig.

Abstrakte Klasse:

public abstract class MyAbstractClass
{
	public abstract void DoSomething();
}

public class MyConcreteClass : MyAbstractClass
{
	public override void DoSomething()
	{
		// ...
	}
}

Interface:

public interface IAmAnInterface
{
	void DoSomething();
}

public class MyConcreteClass : IAmAnInterface
{
	public void DoSomething()
	{
		// ...
	}
}

Man beachte die jeweiligen Schlüsselwörter, die dazugekommen sind.

Halten wir fest: Abstrakte Klassen sind da, um den Quellcode unnötig aufblähen zu lassen.

Das ist natürlich Quatsch 🙂

Abstrakte Klassen haben den Interfaces gegenüber einen riesengroßen Vorteil: Es sind Klassen! Unglaublich aber war 🙂

Und was können Klassen? Richtig! Logik beinhalten. Interfaces haben nämlich keine Logik.

Jedoch haben Interfaces einen weiteren Vorteil: Eine Klasse kann mehrere davon definieren (genauer genommen: implementieren). Jedoch nur von einer einzigen Klasse erben.

Zum guten Umgangston gehören…

… bei einem Interface ein „I“ vor den Anfang. Also sowas wie IList.

Jetzt kann man damit mit der Namensgebung etwas „spielen“ und das I als ein englisches Wort betrachten. Dann entstehen solche Namen wie z. B. ICanBeClosed oder auch IDestroyEverything.

Man kann sich auch an die Microsoft’s Strategie halten und die Interfaces nach Eigenschaften benennen. Beispielsweise: ICloseable oder IDestroyable. Geht auch, ist nur nicht so „lustig“ 🙂

Während beim Interface das I an vorderster Stelle steht, sollte bei abstrakten Klassen das Wörtchen: „Abstract“ davor stehen. Es gibt einige Entwickler, die das nicht so gern sehen. Ich jedoch halte es durchaus für sinnvoll. Ich möchte schließlich auf den ersten Blick sehen, dass hier von einer abstrakten Klasse abgeleitet wird und komme nicht auf die Idee hiervon eine Instanz zu bilden.

Würde beispielsweise eine abstrakte Klasse einfach nur Logger heißen, würde ich direkt eine Instanz von bilden wollen. Bei der Klasse AbstractLogger käme ich da nicht so schnell auf die Idee 🙂

Fazit

Fassen wir noch einmal kurz zusammen:

Es gibt Interfaces und es gibt das „Interface-Prinzip“. Während das Interface nur ein Schlüsselwort aus vielen Programmiersprachen ist, ist das Prinzip so definiert, dass man andere Klassen in (beispielsweise) Interfaces aufteilt und nur mit solchen arbeitet.

Wenn du bereits viele vernünftige Interfaces definiert hast, kannst du dir anschließend deine Klasse relativ einfach auf Basis von Interfaces aufbauen. Genaue Implementierung, spielt jedoch keine übergeordnete Rolle.

Kategorien:
Grundlagen
Das könnte dir auch gefallen
Sei der erste und teile deine Meinung mit der Welt!
... und was meinst du dazu?
Deine E-Mail-Adresse wird nicht veröffentlicht.