Vererbung, Implementierung, Copy/Paste

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 14 Antworten in diesem Thema. Der letzte Beitrag () ist von VaporiZed.

    Vererbung, Implementierung, Copy/Paste

    Hallo,

    ich bastel gerade ein schönes Projekt, wo man richtig gut Klassencode wiederverwenden kann, super objekt orientiert sozusagen. Ich habe mal gelesen Interaces zu implementieren hat Vorteile gegenüber der Vererbung, deswegen wollte ichs damit direkt mal versuchen.
    Allerdings finde ich mich selbst gerade bei der Implementierung dabei wieder auch den Code von Klasse zu Klasse zu kopieren, nur halt diesmal in die vorgeschriebene Sub Hülle.
    Also mehr als die Hüllen spare ich mir da gar nicht im Vergleich zum Copy/Paste Ansatz. Das ist mit Vererbung schon ein ganz anderes Thema.

    Mache ich das falsch? Kann man für Schnittstellen auch fertige Subs definieren? Im Interface selbst zumindest nicht wie es scheint

    Viele Grüße
    In C# geht das zwar, aber nicht in VB.NET.
    Wenn Du viel gleichen Code hast, solltest Du versuchen, eine Klasse daraus zu machen und z.B. mit dem Strategy-Pattern für Unterschiede zu sorgen.
    Dabei wird veränderliches Verhalten als eigenständige Klasse modelliert und dann einer anderen Klasse über Konstruktor oder andere Methode eingepflanzt. Aber das ist natürlich nur eine Möglichkeit, abhängig davon, was Du genau vorliegen hast. Hast Du uns ein Beispiel?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Angenommen ich nützte den Copy/Paste Ansatz, dann hätte ich mehrere Klassen dieser Art. Die Properties können sich unterscheiden, der Rest ist gleich.
    Da hab ich jetzt z.B. die GetData und die Save in ein Interface gepackt, aber am Ende hab ich den Code halt doch reingeschrieben, was ich bei Vererbung natürlich nicht gemacht hätte. Dann dachte ich das macht ja gar kein Sinn.
    Ich kann einfach eine Test-Klasse machen mit den Methoden aber ohne Properties. Viel wird der Code weil ich von den Klassen 6 Stück hab.

    VB.NET-Quellcode

    1. Friend Class Test1
    2. Private Initialized As Boolean
    3. Friend Property p1 As Integer
    4. Friend Property p2 As List(Of String)
    5. Friend Property p3 As Integer
    6. ...
    7. Friend Sub New()
    8. Initialized = False
    9. End Sub
    10. Friend Sub New(id As String)
    11. GetData(id)
    12. End Sub
    13. Private Sub GetData(init As String)
    14. ...
    15. End Sub
    16. Private Sub Save()
    17. ...
    18. End Sub
    19. End Class

    Haudruferzappeltnoch schrieb:

    Die Properties können sich unterscheiden, der Rest ist gleich.
    Dann gehört das gleiche in eine Klasse und die Unterschiede in die anderen. Wenn sich die Properties klassenweise unterscheiden, könntest Du mit Vererbung ja auch nicht innerhalb der Basisklasse auf die unterschiedlichen Properties der Folgeklassen zugreifen. FCoI - favour composition over inheritance. Die unterschiedlichen Klassen behalten ihre Unterschiede und beinhalten zusätzlich ein Objekt der gemeinsames-Verhalten-Klasse. Spezifischer wird es, wenn Du spezifischer wirst. Was machen die 6 Klassen, was sind Gemeinsamkeiten, was Unterschiede?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Ja das ist schon klar, die Properties habe ich nicht mit in der Basisklasse. Es ging mir nur um den Punkt mit den Interfaces.
    Ich habe es nun mit Vererbung versucht.

    Ich möchte in Test1 die GetData von Test verwenden, die muss aber die Fill aus Test1 aufrufen, weil Test hat keine richtige Fill. Ist das so richtig?
    Wenn Fill nur Overridable wäre, würde GetData sich dann abhängig davon ob Test1 die Methode überschreibt aus Test1 oder aus Test an der Fill bedienen?

    VB.NET-Quellcode

    1. Friend MustInherit Class Test
    2. Private Protected Initialized As Boolean
    3. Private Protected Sub GetData()
    4. 'Daten werden geholt, danach an Fill übergeben
    5. Fill(data)
    6. End Sub
    7. Private Protected MustOverride Sub Fill(Data As Object())
    8. End Class
    9. Friend Class Test1
    10. Inherits Test
    11. Friend Sub New()
    12. Initialized = False
    13. End Sub
    14. Friend Sub Initialize()
    15. If Initialized Then Exit Sub
    16. GetData()
    17. End Sub
    18. Private Protected Overrides Sub Fill(Data As Object())
    19. 'füllt die jeweiligen Properties
    20. Initialized = True
    21. End Sub
    22. End Class

    Haudruferzappeltnoch schrieb:

    Wenn Fill nur Overridable wäre, würde GetData sich dann abhängig davon ob Test1 die Methode überschreibt aus Test1 oder aus Test an der Fill bedienen?
    Ja.

    Haudruferzappeltnoch schrieb:

    weil Test hat keine richtige Fill. Ist das so richtig?
    Keine "richtige" ist eine völlig falsche Formulierung.
    Class Test ist halt eine "richtige" Basisklasse, die selbst und von der einige Prozeduren abgeleitet werden müssen.
    Diese Prozeduren sind in der Basisklasse deklariert.
    Ich würde es für sinnvoll halten, für die Daten ebenfalls eine Daten-Basisklasse oder etwas äquivalentes zu implementieren, damit da nicht das Object-Array übergeben werden muss.
    Diese Daten-Basisklasse kannst Du serialisierbar bestalten, um sie leicht speichern und laden zu können.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ich würd das dann eher so gestalten:

    VB.NET-Quellcode

    1. Friend Datenklasse
    2. Function GetData() As IEnumerable(Of WasAuchImmer)
    3. Dim GesammelteDaten As New List(Of WasAuchImmer)
    4. 'irgendwie die Daten sammeln, scheint ja für alle Klassen gleich zu sein
    5. Return GesammelteDaten
    6. End Function
    7. End Class
    8. Friend AndereKlasse
    9. Private ReadOnly Datenklasse As New Datenklasse
    10. Sub Fill()
    11. Dim Daten = Datenklasse.GetData()
    12. 'mit Daten machen, was man will
    13. End Sub
    14. End Class

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Haudruferzappeltnoch schrieb:

    dieses Array
    Welches meinst Du?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Untypisierte Daten und Verwendung von Vererbung - ob man das als schlecht bezeichnen will, muss man selber entscheiden. Ich wollte nur eine Alternative zeigen.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Haudruferzappeltnoch schrieb:

    Ich habe mal gelesen Interaces zu implementieren hat Vorteile gegenüber der Vererbung,....
    Lesen bildet (äh - leider nicht immer und unbedingt)

    Haudruferzappeltnoch schrieb:

    Allerdings finde ich mich selbst gerade bei der Implementierung dabei wieder auch den Code von Klasse zu Klasse zu kopieren, nur halt diesmal in die vorgeschriebene Sub Hülle.
    Aha!
    Es gibt also auch Nachteile (von Interaces gegenüber der Vererbung)!
    @RodFromGermany
    Na nur ein Array wurde hier im Sinne einer Übergabe diskutiert. Das Object Array data in Fill()
    @VaporiZed
    Du ersetzt das Object Array durch List(Of WasAuchImmer) allerdings kann ich WasAuchImmer nicht definieren. Denn das sind die Typen der Properties jeder Derived Klasse. Und die sind ja immer unterschiedlich. Also bestenfalls brauche ich Für jede Klasse eine weitere Datenklasse und am Ende sind nur primitive Datentypen drin. Und auch die Datenklasse kriegt die auch nicht typisiert, das würde die dann selbst erstmal konvertieren.

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

    Da jetzt erstmal nix konkret vorliegt: Warum willst Du überhaupt eine Basisklasse haben, wenn die Datenladefunktion eh folgeklassenspezifisch ist?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Na das ist sie ja eigentlich nicht, ich lese eine Zeile aus einer Tabelle mit SqlDataReader.GetValues und das gibt immer ein Object Array zurück. Der CommandText wird von der Derived Klasse hingegen vorgegeben, jeder hat eine andere Tabelle. Genauso wie eben die Fill Methode um die Properties zu berücksichtigen. Also das Lesen ist immer gleich aber die Beschaffenheit anders.
    Anders ausgedrückt hab ich nunmal 20 Zeilen in jeder Klasse gleich, das kann ja auch nicht richtig sein. Ich wollte den Code weniger redundant machen. Nach meiner Auffassung ist die Datenladefunktion GetData
    Ok, dann hast Du also jetzt 2 Möglichkeiten: Komposition (Composition, Black Box), Vererbung (Inheritance, White Box).
    Komposition: Du nutzt in allen Klassen eine andere Klasse, die die Daten lädt und zur Verfügung stellt.
    Vererbung: Du nutzt in allen Klassen die Basisklassenfunktion, die die Daten lädt und zur Verfügung stellt.

    Was Du nutzt, bleibt Dir überlassen.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.