Interfaces - Wozu sind sie gut und wie verwendet man sie?

  • VB.NET

Es gibt 16 Antworten in diesem Thema. Der letzte Beitrag () ist von Amro.

    Interfaces - Wozu sind sie gut und wie verwendet man sie?

    Guten Tag

    Da ich immer wieder etwas dazulernen will, habe ich mir gedacht ich gucke mir mal die Interfaces genauer da. Jetzt würde ich gerne wissen wozu sie gut sind also wozu man sie benutzt und wie man sie benutzt.

    Vielen Dank im Voraus

    MfG
    Breadsoft
    Interfaces brauchst du immer dann, wenn eine Klasse verschiedene Vererbbare Eigenschaften besitzen soll. In .Net kann eine Klasse nur eine Basisklasse besitzen, um Probleme von Vielfachvererbung zu vermeiden. Um dennoch ähnliche Funktionalität zu bieten wurden die Interfaces eingeführt (eigentlich ist ein Interface nur eine abstrakte Klasse). In Interfaces können aber keine Member implementiert werden, sondern Interfaces schreiben nur vor, welche Member die Abgeleiteten klassen enthalten müssen. Siehe auch hier.
    Zusätzlich gibt es noch speziellere Dinge wie z.B. ComInterfaces :)
    Da brauchst du aber nicht unbedingt ein Interface zu erstellen sondern kannst auch direkt mit Pointern arbeiten. Jedoch ist Interfaces erstellen das übliche.


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
    Hi
    man kann sich Interfaces im allgemeinen wirklich als abstrakte Schicht darstellen. Es kommt nicht darauf an, wie etwas implementiert wird, sondern es ist eine vollständige Trennung. Jede Klasse ist nur an den Sinn, der im Interface steckt und die Spezifikation für Fälle gebunden, nicht aber an die konkrete Implementierung. Ein einfaches Beispiel sind zwei ICollection(Of T): LinkedList(Of T) und List(Of T). List(Of T) arbeitet intern mit einem Array, bei einer LinkedList(Of T) zeigt ein Element immer auf das nächste. Bereitgestellt werden hierbei nur einfache Operationen, wie Add, Remove, Contains und Count, die beide Listen zur Verfügung stellen. Wie vorhin erklärt, sind Arrays und verkettete Listen aber komplett unterschiedliche Listen, aber sie funktionieren nach außen hin aus Sicht des Interfaces identisch.

    Gruß
    ~blaze~
    Nein, ein Interface ist keine Klasse. Interfaces und Klassen sind beides Typen, aber sie haben mehr oder weniger große Unterschiede.
    Der Ersteller legt den ZWECK fest, derjenige, der das Interface implementiert letztendlich aber, wie dieser Zweck umgesetzt wird.
    Versuche einfach mal folgendes Interfaces abstrakt zu modellieren:
    - IFileSystem, eine abstrakte Sicht auf ein Dateisystem unter Verwendung von Uri oder anderen Bezeichnern (muss ja noch nicht unbedingt generalisiert werden), Beispiele sind zum Beispiel Ftp oder das lokale Dateisystem
    - IRenderable, kann auf Graphics-Objekte gezeichnet werden, hierbei kann zeichnet jedes IRenderable nur sich selbst, aber konkrete Implementierungen können zum Beispiel eine ICollection(Of IRenderable) besitzen oder nur ein Bild zeichnen (wäre übrigens ein Kompositum)
    und überlege dir Beispiele dazu. Außerdem warum gibt es folgendes als Interfaces und warum werden die nicht direkt auf Object definiert?
    - IClonable, erzeugt eine Kopie von sich selbst
    - IEnumerable(Of T), listet enthaltene Elemente auf

    Spoiler anzeigen

    - IFileSystem:

    VB.NET-Quellcode

    1. Public Interface IFileSystem
    2. Function GetFiles() As IEnumerable(Of Uri)
    3. Function GetDirectories() As IEnumerable(Of IFileSystem)
    4. ReadOnly Property Identifier As Uri
    5. Sub MoveFile(source As Uri, destination As Uri)
    6. '...
    7. End Interface

    - IRenderable

    VB.NET-Quellcode

    1. Public Interface IRenderable
    2. Sub Draw(ByVal surface As Graphics)
    3. End Interface


    - IClonable:
    es ist nicht bekannt, wie Clonable zu implementieren ist. Jede Klasse weiß nur von sich selbst, ob und wie sie ein Duplikat von sich erstellt. Es kann ja zum Beispiel auch sein, dass ein internes Objekt unveränderlich ist und daher von beiden Klassen geteilt werden kann.
    - IEnumerable(Of T):
    Nicht jedes Objekt ist auflistbar. Wenn ein Objekt nicht mehrere Objekte enthalten oder generieren kann, macht es keinen Sinn.


    Gruß
    ~blaze~

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „~blaze~“ ()

    Hab's oben noch mal editiert.
    IDisposable zum Beispiel ist auch ein gutes Beispiel. IDisposable hat den Zweck, dass von einem Objekt verwendete Daten freigegeben werden, also ihre Daten gelöscht werden. Die konkrete Implementierung von IDisposable ist zwar Typabhängig, da zum Beispiel Image, Bitmap, Graphics, Icon, aber auch Stream, Control, etc. diesen Typ implementieren. Der Zweck, der mit der Dispose-Methode verbunden wird, ist, dass das Objekt freigegeben wird, auf dem Dispose aufgerufen wird. Somit wird zum Beispiel ein Stream geschlossen oder die einem Bild zugrundeliegenden Daten im Speicher freigegeben. Was genau Dispose aber wirklich tut - es kann auch u.U. nichts tun - ist der Klasse selbst überlassen. Daher ist das eine Abstrakte Sicht auf der Verhalten. Es ist aber in jedem Zusammenhang klar, wann genau Dispose zu verwenden ist, nämlich dann, wenn die Resource nicht mehr verwendbar ist.

    Gruß
    ~blaze~
    Ach ja, da du grad IDisposable ansprichst. Microsoft gibt, da eine spezielle Implementierung vor die man einhalten sollte. Also nicht was und wie freigegeben wird sondern wie die Methode implementiert werden sollte. Siehe einfach unten das Beispiel: msdn.microsoft.com/de-de/libra…cs-lang=vb#code-snippet-4
    Gleich richtig angewöhnen. Ich musste umstellen :P


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
    Interfaces werden gerne bei PlugIns verwendet. Man kann damit der PlugIn-Klasse vorschreiben, was sie können muss.
    Da gibt's beispielsweise eine Interfaces.dll, die nur die PlugIn-Interfaces enthält. Ein Beispiel wäre:
    Interfaces.dll:

    VB.NET-Quellcode

    1. Public Interface IPlugIn
    2. Inherits IDisposable
    3. ReadOnly Property DisplayName As String
    4. ReadOnly Property PlugInGuid As Guid
    5. Sub OnLoad()
    6. Function GetStringFromInteger(Value As Integer) As String
    7. End Interface
    (Nebenbei: Interfaces fangen immer mit dem Buchstaben I an. Das klingt jetzt vielleicht unnötig, aber das gesamte .Net-Framework hält sich an diesen Standard und das hilft, Ordnung zu halten.)

    Also jedes PlugIn muss einen DisplayName haben. Dann gibt es eine GUID, die zum Identifizieren verwendet wird.
    Die Sub OnLoad wird beim Laden des PlugIns ausgeführt. Dann gibt's noch GetStringFromInteger. Das Program, das das PlugIn verwendet, will vom PlugIn nur, dass es einen Integer in einen String verwandelt. Wie das PlugIn das macht, ist dem Programm egal.

    Beachte Zeile 2. Das Interface enthält nicht nur die gerade aufgezählten Member, sondern auch die von IDisposable.
    Für den Fall, dass ein PlugIn unverwaltete Ressourcen anlegt (z.B. System.Drawing.Bitmap), die verworfen werden müssen, ist das genau das richtige. (Siehe auch Edit am Ende des Posts)

    Das wäre ein Beispiel für eine Verwendung:
    Das Programm verweist auf die Interfaces.dll

    VB.NET-Quellcode

    1. Imports System.Reflection
    2. Public Class Form1
    3. Dim PlugIns As New List(Of Interfaces.IPlugIn) 'Alle PlugIn-Instanzen werden in dieser Liste gespeichert.
    4. Private Sub LoadPlugIns()
    5. For Each i In System.IO.Directory.GetFiles("PlugIn-Ordner") 'Alle PlugIn-Assemblies werden aus dem PlugIn-Ordner geladen
    6. Dim PlugInLib = Assembly.Load(i)
    7. For Each j In PlugInLib.GetTypes 'Eine Assembly kann mehrere PlugIns enthalten.
    8. If j.GetInterfaces.Contains(GetType(Interfaces.IPlugIn)) Then 'Hier wird überprüft, ob der Typ das Interface implementiert, also ob er als PlugIn verwendet werden kann.
    9. Dim PlugInInstance = DirectCast(Activator.CreateInstance(j), Interfaces.IPlugIn) 'Hier wird über den Activator eine Instanz des PlugIn-Typs erzeugt.
    10. PlugInInstance.OnLoad() 'Dann wird OnLoad aufgerufen, um dem PlugIn zu sagen, dass es geladen wurde.
    11. PlugIns.Add(PlugInInstance) 'Und es wird abgelegt.
    12. End If
    13. Next
    14. Next
    15. End Sub
    16. Private Sub DisposePlugIns()
    17. For Each i In PlugIns 'Hier werden alle PlugIns verworfen.
    18. i.Dispose()
    19. Next
    20. End Sub
    21. End Class


    Die PlugIns können jetzt verwendet werden. Hier ein Beispiel für ein PlugIn:
    In einer Klassenbibliothek gibt's die Klasse MyPlugIn. Die Klassenbibliothek verweist ebenfalls auf die Interfaces.dll.

    VB.NET-Quellcode

    1. Public Class MyPlugIn
    2. Implements Interfaces.IPlugIn
    3. Private Shared ReadOnly InternalGuid As New Guid("c3c10b0d-8097-49ed-b845-8e53c945d2b2") 'Diese GUID wird für dieses PlugIn verwendet. Sie ist für alle MyPlugIn-Instanzen gleich.
    4. Public ReadOnly Property DisplayName As String Implements Interfaces.IPlugIn.DisplayName
    5. Get
    6. Return "PlugIn Test 1"
    7. End Get
    8. End Property
    9. Public ReadOnly Property PlugInGuid As System.Guid Implements Interfaces.IPlugIn.PlugInGuid
    10. Get
    11. Return InternalGuid
    12. End Get
    13. End Property
    14. Public Sub OnLoad() Implements Interfaces.IPlugIn.OnLoad
    15. MessageBox.Show("PlugIn Test 1 geladen.") 'Hier nur ein Beispiel. Hier könnten beispielsweise Ressourcen geladen werden oder ähnliches.
    16. End Sub
    17. Public Sub Dispose() Implements IDisposable.Dispose
    18. 'Keine Ressourcen zu verwerfen.
    19. End Sub
    20. Public Function GetStringFromInteger(Value As Integer) As String Implements Interfaces.IPlugIn.GetStringFromInteger
    21. Return Convert.ToString(Value, 2).PadLeft(32, "0"c) 'Gibt die Zahl in Binärform zurück. Voranstehende Nullen werden bis 32 Zeichen aufgefüllt.
    22. End Function
    23. End Class


    So. Ein Aufrufbeispiel für solche PlugIns wäre das hier:
    Kommt ebenfalls in die Form1-Klasse.

    VB.NET-Quellcode

    1. Private Sub ExecutePlugIns() Handles Button1.Click
    2. Dim TestValue = 624146 'Der zu konvertierende Wert.
    3. Dim Results As New List(Of String)
    4. For Each i In PlugIns
    5. Results.Add(i.DisplayName & ": " & i.GetStringFromInteger(TestValue)) 'Jede Zeile der MessageBox zeigt den DisplayName und das Ergebnis.
    6. Next
    7. MessageBox.Show(String.Join(Environment.NewLine, Results))
    8. End Sub

    Das ist das Ergebnis:

    Ich habe testweise ein zweites PlugIn hinzugefügt, das die Zahl in hexadezimale Schreibweise umwandelt.




    Das ist nur ein Beispiel für die Verwendung eines Interfaces.
    Genau das selbe würde sich auch mit einer Klasse implementieren lassen:

    VB.NET-Quellcode

    1. Public MustInherit Class InterfaceBase
    2. Implements IDisposable
    3. Public MustOverride ReadOnly Property DisplayName As String
    4. Public MustOverride ReadOnly Property PlugInGuid As Guid
    5. Public MustOverride Sub OnLoad()
    6. Public MustOverride Function GetStringFromInteger(Value As Integer) As String
    7. Public MustOverride Sub Dispose() Implements IDisposable.Dispose
    8. End Class

    Das Interface hat aber den Vorteil, dass der PlugIn-Ersteller die PlugIns trotzdem von einer Basisklasse ableiten kann. Wenn er mehrere ähnliche PlugIns erstellt, kann er die Vererbung gezielter ausnutzen.




    Edit: Weil IDisposable angesprochen wurde:
    Ich denke, dass das Interface hier nur eine Vereinheitlichung schaffen soll. Mir würde kein Grund einfallen, irgendwo eine List(Of IDisposable) zu verwenden. Außer man hat einen ResourceDisposer, dem man einen IEnumerable(Of IDisposable) gibt... aber wofür?
    Übrigens:
    Die korrekte Implementierung wird von Visual Studio direkt eingefügt:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Class Foo
    2. Implements IDisposable
    3. #Region "IDisposable Support"
    4. Private disposedValue As Boolean ' So ermitteln Sie überflüssige Aufrufe
    5. ' IDisposable
    6. Protected Overridable Sub Dispose(disposing As Boolean)
    7. If Not Me.disposedValue Then
    8. If disposing Then
    9. ' TODO: Verwalteten Zustand löschen (verwaltete Objekte).
    10. End If
    11. ' TODO: Nicht verwaltete Ressourcen (nicht verwaltete Objekte) freigeben und Finalize() unten überschreiben.
    12. ' TODO: Große Felder auf NULL festlegen.
    13. End If
    14. Me.disposedValue = True
    15. End Sub
    16. ' TODO: Finalize() nur überschreiben, wenn Dispose(ByVal disposing As Boolean) oben über Code zum Freigeben von nicht verwalteten Ressourcen verfügt.
    17. 'Protected Overrides Sub Finalize()
    18. ' ' Ändern Sie diesen Code nicht. Fügen Sie oben in Dispose(ByVal disposing As Boolean) Bereinigungscode ein.
    19. ' Dispose(False)
    20. ' MyBase.Finalize()
    21. 'End Sub
    22. ' Dieser Code wird von Visual Basic hinzugefügt, um das Dispose-Muster richtig zu implementieren.
    23. Public Sub Dispose() Implements IDisposable.Dispose
    24. ' Ändern Sie diesen Code nicht. Fügen Sie oben in Dispose(ByVal disposing As Boolean) Bereinigungscode ein.
    25. Dispose(True)
    26. GC.SuppressFinalize(Me)
    27. End Sub
    28. #End Region
    29. End Class
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Niko Ortner“ ()

    Dachte vielleicht gibt es da wieder eine Regel die besagt das nur Methoden aus
    dem Inteface benutzt werden dürfen.
    Kann ich davon ausgehen das Interfaces eigentlich nur interessant sind wenn man in Gruppen arbeitet oder
    wenn eine mehrfach Veerbung realisiert werden soll.
    Sehe für mich kein grossen Nutzen ehrlich gesagt.
    selbst implementieren musst du sie so gut wie nie.
    Ausser - wurde schon gesagt - bei einem Plugin-System.
    Und auch bei Remoting.
    Achja - auch bei LowLewel-Com-InterOp.
    Also gibt sicher noch einige Sachen mehr, aber halt alles ausgewiesene Spezialgebiete.

    Normal fährst du mit gut durchdachten Basisklassen wesentlich besser.


    Nur dass du Interfaces nie brauchst ist wohl ein Witz.
    Jede ForEach-Schleife beruht auf dem IEnumerable(Of T) - Interface.
    Jede Suche nach Daten basiert auf IComparable(Of T) - oder einem ähnlichen Interface

    Gugget auch hier, wenn ihr Zeit zu lesen habt ;) Unterschied zwischen abstrakten Klassen und Interfaces

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()