Interfaces - wozu?
-
Hallo zusammen!
Ich bin relativ neu in der C#-Materie und bin nun über den Begriff Interfaces gestolpert. Ich habe auch schon anhand verschiedener Quellen (unter anderem der MSDN und meinem C# Programmierbuch) einiges über Interfaces gelesen.
Dennoch ist mir der genaue Nutzen dieser Interfaces noch ein wenig schleierhaft. Sicher, das mit der Mehrfachvererbung scheint mir durchaus logisch, da dies halt unter .NET nicht anders realisierbar ist.
Aber das kann doch nicht alles sein, oder? Und die Aussage, dass man mit Interfaces implementierende Klassen dazu bringt, gewisse Methoden und Eigenschaften garantiert zu implementieren, erscheint mir halt nicht so ganz notwendig. Ich kann doch theoretisch die entsprechenden Methoden und Felder auch ohne Interface in die Klassen mit aufnehmen...wozu also der Aufwand mit den Interfaces?
Ich arbeite gerade an einem konkreten "Projekt", in dem ich unter anderem eine Art "Arbeiter-Klasse" habe, die verschiedene Methoden bereit stellt um Daten aus einer Datei auszulesen und entsprechend zurück zu geben.
Jetzt habe ich mir überlegt, dass ich mit den Interfaces diese Methoden quasi kategorisieren könnte (in meinem Fall z.B. in "normales" Datei I/O und einmal über eine spezielle Library, die andere Funktionen nutzt).
Das würde in meinen Augen dem Nutzer dieser Arbeiter-Klasse das Benutzen erleichtern, da er halt anstatt ein Objekt der Klasse zu erzeugen ein Objekt des entsprechenden Interfaces erzeugt, quasi:
ISC2Utils_Raw m_UtilsRaw; m_UtilsRaw = new SC2Utils();
"ISC2Utils_Raw" ist der Name eines der Interfaces, welche von der Arbeiter-Klasse "SC2Utils" implementiert werden.
Auf diese Weise würde man dann auch nur die Methoden als Benutzer sehen, die für die entsprechende Aufgabe des Interfaces nötig sind. Also quasi eine Art Maske über die Arbeiter-Klasse, welche für eine bestimmte Aufgabe unnötige Methoden der Klasse "unsichtbar" macht.
Ist diese Art der Nutzung von Interfaces kompletter Schwachsinn oder macht ihr das hier und da auch so? Würde mich freuen, wenn ihr mir dabei helfen könntet, diese Dinger etwas besser zu verstehen
Danke & Gruß
Skubi
-
Du kannst mit Interfaces Implementierung und Verwendung entkoppeln. Das ist der eigentliche Sinn.
Das geht zwar auch mit Vererbung, allerdings stört da bei C# dass Mehrfachvererbung nicht erlaubt ist.Das würde in meinen Augen dem Nutzer dieser Arbeiter-Klasse das Benutzen erleichtern, da er halt anstatt ein Objekt der Klasse zu erzeugen ein Objekt des entsprechenden Interfaces erzeugt, quasi:
Interfaces kann man nicht instanzieren, nur konkrete Klassen.
-
Wie hustbaer schon sagte sind Interfaces dazu da Definition und Implementierung zu trennen. Ganz einfach aus dem Grund, weil du nicht wissen musst, was eine Klasse alles tut, sondern nur ein Interface, dass die Funktionalität bereitstellt die du benötigst.
Kleines Beispiel:
static void Print(IEnumerable sequence) { foreach(var item in sequence) Console.WriteLine(item); }
Print kann jetzt mit einem String, einem Array, einer Liste oder sonst etwas aufgerufen werden, es muss nur IEnumerable implementiert werden. Trotzdem weißt du, egal von welcher Klasse das übergebene Objekt tatsächlich ist, wie man alle Elemente bekommt.
Dieser spezielle Fall der Verwendung von Interfaces den du hier beschreibst wird oft beim TDD verwendet (test-driven development). Durch die Verwendung von Interfaces lassen sich die Klassen von einander entkoppeln und einzeln testen.
-
TDD schrieb:
Dieser spezielle Fall der Verwendung von Interfaces den du hier beschreibst wird oft beim TDD verwendet (test-driven development). Durch die Verwendung von Interfaces lassen sich die Klassen von einander entkoppeln und einzeln testen.
Huch?
Er beschreibt - wenn ich es richtig verstehe - eine Gottklasse, deren (zu) viele Funktionen er mit Hilfe von Interfaces in verschiedene Gruppen unterteilt.
Auf jeden Fall klingt es für mich nicht gut. Verbindung zu TDD kann ich auch keine erkennen.
-
Interfaces kann man nicht instanzieren, nur konkrete Klassen.
Dessen bin ich mir wohl bewusst. Deshalb habe ich ja versucht anhand meines Beispiel-Codes den Sachverhalt zu verdeutlichen. Ich würde das nach dem Motte...
<INTERFACE> Variablenname = new <KLASSEN_DIE_INTERFACE_IMPLEMENTIERT>();
tun.
Er beschreibt - wenn ich es richtig verstehe - eine Gottklasse, deren (zu) viele Funktionen er mit Hilfe von Interfaces in verschiedene Gruppen unterteilt.
Genau das ist das, was ich meinte. Wäre in meinen Augen halt interessant, wenn man z.B. die Klasse für andere Leute zugänglich machen möchte, die die genaue Arbeitsweise der Klasse nicht kennen und nicht wissen, welche der Funktionen für welche Aufgaben da sind.
Aber wie ich das so raus höre, ist diese Vorgehensweise nicht so das, wofür man Interfaces normalerweise nutzt, ja?
Gruß
Skubi
-
Du schreibst sehr allgemein, daher kann man auch schwer was konkretes sagen.
Ich habe aber den Eindruck, dass du dein Software-Design von der falschen Seite aus angehst.Erst eine Klasse machen die 100 verschiedene Dinge "kann", und diese dann mit Interfaces zu gruppieren, erscheint mir fragwürdig.
Wieso zerschneidest du deine Gottklasse nicht lieber in Klassen die nur eine Aufgabe erfüllen?
-
Skubidus schrieb:
<INTERFACE> Variablenname = new <KLASSEN_DIE_INTERFACE_IMPLEMENTIERT>();
Hier bieten sich dann Fabrikmuster oder Dependency-Injection an um die Implementierung vollständig zu kapseln.
-
Vielleicht verständlicher, wenn man ein konkretes Beispiel heranzieht.
Ich arbeite gerade an einem konkreten "Projekt", in dem ich unter anderem eine Art "Arbeiter-Klasse" habe, die verschiedene Methoden bereit stellt um Daten aus einer Datei auszulesen und entsprechend zurück zu geben.
Überlege dir mal was du wohl tun würdest, wenn du die Daten nun nicht mehr (oder nicht nur) aus einer Datei lesen wolltest, sondern z.B aus einer Datenbank?
Was würdest du tun, wenn aus Kompatibilitätsgründen mit alten Datenquellen beide Methoden verwendet werden müssten?
Bei der Ersten Variante, könntest du einfach das interne deiner Arbeiterklasse ändern und der Rest des Quellcodes würde sich nicht wirklich ändern. Mal abgesehen davon dass die Verbindungsdaten dann hardcodiert in der Klasse ständen.
Doch geht dabei die alte Vorgehensweise verloren. Würdest du beide Methoden anbieten wollen, hättest du ohne Interfacegedöns eine Steuerlogik zu implementieren, müsstest also dennoch bereits funktionierenden Code anfassen und ändern. Das ist nicht nur aufwändig, sondern auch fehleranfällig.Hier kommen jetzt die Interfaces ins Spiel
Aber das kann doch nicht alles sein, oder? Und die Aussage, dass man mit Interfaces implementierende Klassen dazu bringt, gewisse Methoden und Eigenschaften garantiert zu implementieren, erscheint mir halt nicht so ganz notwendig.
Dass implementirende Klassen gezwungen sind alle Methoden zu implementieren, geht weit über eine syntaktische Eigenheit der Sprache hinaus. Dabei gilt es Dinge zu beachten, die durch das bloßse Implementieren der Methoden nicht abgedeckt werden.
Hinter einem Interface, steht immer eine Spezifikation (oder sollte so sein). Die Spezifikation ist ersteinmal völlig unabhängig von irgendeiner Programmiersprache und mit welchen Mitteln diese Umgesetzt werden kann.
Allgemein lässt sich ausdrücken, solange gewisse Vorbedingungen erfüllt sind, stellt der Aufruf einer Operation aus der Spezifikation bestimtme Nachbedingungen her.Spezifikationen werden immer mitvererbt, dürfen gelocket werden, jedoch nicht strenger sein. Mit anderen Worten, alle deine Abgeleiteten Klassen müssen überall dort eingesetzt werden können, wo das Interface benutzt wird.
Und dieser Gedanke entspricht auch dem Sinn des Interfaces. Denn unabhängig davon ob du nun ne Klasse verwendest die ne Datei ausliest, eine Datenbank oder die Daten sonstwie beschafft, der Quellcode welche das Interface einfach nur benutzt kann das ziemlich egal sein und muss auch niemals angepasst werden, egal wie viele Varianten deiner Arbeiterklasse auch immer hinzukommen mögen.cu
-
Da ich mehr oder weniger das selbe Problem zur Zeit habe würde mir ein Beispielcode deiner Aussage wirklich weiterhelfen "Ka-Mensch".
Lg, zerocool