OOP und Klassenhierarchien

andy_m4

Vice Admiral
Registriert
Aug. 2015
Beiträge
7.009
Der Artikel Why extends is evil beschäftigt sich mit der Frage der Vererbung innerhalb von Klassenhierarchien und welche Probleme dabei auftreten können.

Konkret geht es vor allem um das Fragile Base Class Problem, dass dann auftritt, wenn man zu inflexibel designte Basisklassen hat und daran Änderungen vornehmen muss, was dazu führen kann, dass man großflächige Schäden in deren Ableitungen anrichtet.
Vermeiden kann man das durch Einsatz von Interfaces, wie es im Java-Sprech heißt.

Das spiegelt auch meine Erfahrung wider. Was meint ihr dazu?

Btw: Netter Quote von James Gosling:
During the memorable Q&A session, someone asked him: "If you could do Java over again, what would you change?" "I'd leave out classes," he replied.
 
Deckt sich mit meiner Wahrnehmung. Vererbung scheint als Konzept größtenteils "gescheitert". Neuere Sprachen wie Go lassen Vererbung sogar bewusst raus. Die Problematik löst man über dann über Interfaces oder Composition (oder eine Kombination).

Der Artikel ist schon eine Weile in meinem Lesezeichen-Sammelsorium. Fand' ich damals recht gut. Bezieht sich zwar konkret auf Perl, passt aber dennoch: http://blogs.perl.org/users/sid_burn/2014/03/inheritance-is-bad-code-reuse-part-1.html
 
Das Thema "composition over inheritance" ist ein Klassiker. Das Problem mit Interfaces ist, dass man schnell viele Klassen generiert, großer Vorteil ist die Vermeidung von Abhängigkeiten. Aus praktischen Gründen setze ich Vererbung aber hin und wieder ein.
 
Servus!

Etliche Jahre zurück predigte die Gang of Four fast schon religiös die extensive Nutzung von Klassen und auch Vererbung bis in den Himmel (creational pattern). Zu einer Zeit als ich noch studierte war die (Über)Abstrahierung das Maß der Dinge und ich habe mich nie besonders damit anfreunden können - so wurde es aber unterrichtet. Es freut mich zumindest (persönlich), dass man langsam davon abzukehren scheint. Ich empfehle mal den Sprung ins .NET Universum, wo Interfaces schon viele Jahre früher gängige(re) Praxis waren. Vererbungen versuche ich möglichst zu vermeiden.


Etwas OT: In einer Zeit, wo beinahe nur noch mit riesigen Frameworks programmiert wird und die Leute den Bezug zu grundsätzlichen und fundamentalen Überlegungen zu verlieren scheinen, ist der Artikel wirklich sehr erfrischend. Danke dafür.

Stefan
 
Ja. Der Gag ist ja, dass uns OOP ja gerade wegen Vererbung verkauft wurde. Nämlich in Hinblick auf Codewiederverwendung. Das trifft ja auch zum Teil durchaus zu. Aber doch offenbar nicht in dem Maße, wie man sich vorher gedacht hatte.

Das macht man stattdessen jetzt tatsächlich via Komposition unterstützt durch Mixins bzw. Traits.
 
Wie ich gerade gestern in einem anderen Thread schrieb: IMHO ist Vererbung - insbesondere die "implementation inheritance", also das Ableiten von konkreten Klassen - der meistüberschätzte Aspekt der OOP. Fragile Base Class ist eins der Probleme, aber auch, dass gerade Neulinge dazu tendieren, sie in Situationen einzusetzen, die nicht gut dafür geeignet sind.

Die Faustregel lautet, dass Vererbung eine "ist-ein"-Beziehung ausdrückt: Hat jedes Objekt vom Typ B auch immer den Typ A? Dann ist "B extends A" zulässig. Sonst nicht.

Noch konkreter kommt diese Regel in Liskovs Substitutionsprinzip zum Ausdruck: Überall, wo ein A als Argument erwartet wird, muss ein B funktionieren wie erwartet. Sonst ist die Vererbung falsch. Diese Formulierung ist noch besser, weil "jedes B ist ein A" auch bedeuten kann, dass B alle Bedingungen von A erfüllt (und evtl. noch weitere dazu). Beispiel: Ein Quadrat erfüllt alle Bedingungen eines Rechtecks, also sagen wir, dass alle Quadrate Rechtecke sind. Hier ist mit "ist ein" aber gemeint, dass ein B alle Fähigkeiten von A haben muss (und evtl. noch weitere). Ein Rechteck hat die Fähigkeit, seine Seitenlängen unabhängig voneinander ändern zu können. Ein Quadrat kann das nicht, wenn es ein Quadrat bleiben will, also ist es kein Rechteck im Sinne des LSP.

Ich würde extends nicht in Bausch und Bogen verdammen, aber sehr zurückhaltend damit umgehen - besonders an wichtigen Stellen, also in meiner Domänenlogik. Gerade dort gilt ohnehin die Empfehlung "depend on abstractions, not on concretions", für die der Einsatz von Interfaces sehr förderlich ist. Oder halt von abstrakten Klassen, die in meinen Augen bei der Vererbung immer noch das deutlich geringere Übel darstellen (verglichen mit konkreten), wenn man sie denn sinnvoll angeht.

@MrFlip0815: Du kannst die creational patterns der GoF auch super mit Interfaces implementieren.
 
The Ripper schrieb:
Kennt jemand Fälle, wo Vererbung "the way to go" ist?

Nope, man kann wirklich alles ohne Vererbung lösen!
Man kann auch komplett ohne OOP programmieren (je nach Sprache mehr oder weniger).

Ein paar sehr schlechte Beispiele für Vererbung - welches aber leider in fast allen UI-Frameworks so gelebt wird:

Code:
Delphi (Grenzwertig):
System.TObject 
  Classes.TPersistent
    Classes.TComponent
      Controls.TControl
        Controls.TWinControl
          StdCtrls.TButtonControl
            StdCtrls.TButton


Swing (Grenzwertig):
     java.lang.Object
        java.awt.Component
            java.awt.Container
                javax.swing.JComponent
                    javax.swing.AbstractButton
                        javax.swing.JButton 

Winforms (Grenzwertig):
System.Object
  System.MarshalByRefObject
    System.ComponentModel.Component
      System.Windows.Forms.Control
        System.Windows.Forms.ButtonBase
          System.Windows.Forms.Button

XAML (WTF?):
System.Object
  System.Windows.Threading.DispatcherObject
    System.Windows.DependencyObject
      System.Windows.Media.Visual
        System.Windows.UIElement
          System.Windows.FrameworkElement
            System.Windows.Controls.Control
              System.Windows.Controls.ContentControl
                System.Windows.Controls.Primitives.ButtonBase
                  System.Windows.Controls.Button

Java FX (WTF?):
     java.lang.Object
        javafx.scene.Node
            javafx.scene.Parent
                javafx.scene.layout.Region
                    javafx.scene.control.Control
                        javafx.scene.control.Labeled
                            javafx.scene.control.ButtonBase
                                javafx.scene.control.Button

Unreal Engine (Naja...):
  UObjectBase
    UObjectBaseUtility
      UObject
        UVisual
          UWidget
            UPanelWidget
              UContentWidget
                UButton
 
Zuletzt bearbeitet:
andy_m4 schrieb:
Ja. Der Gag ist ja, dass uns OOP ja gerade wegen Vererbung verkauft wurde. Nämlich in Hinblick auf Codewiederverwendung. Das trifft ja auch zum Teil durchaus zu.

Auf der anderen Seite bewirkt Vererbung eigentlich auch genau das Gegenteil. Code Wiederverwendbarkeit erreicht man am ehesten durch Kapselung, so das Codeteile über ihre stabile API wiederverwendbar werden. Aber genau diese Kapselung bricht man bei der Vererbung auf.

Ich würd Vererbung deswegen jetzt aber auch nicht komplett verteufeln. Es ist ein valides Werkezeug, man sollte nur drauf achten wann und wie man es einsetzt. Ich hab da schon früher mal von jemanden die Aussage gelesen das flache Vererbungshierarchien deutlich zu bevorzugen wären.


PS: die Aussage von Douglas Crockford bezieht sich zwar eigentlich auf JavaScript, ich finde aber sie gilt universell:

Because objects in JavaScript are so flexible, you will want to think differently about class hierarchies. Deep hierarchies are inappropriate. Shallow hierarchies are efficient and expressive.
 
Finalspace schrieb:
Ein paar sehr schlechte Beispiele für Vererbung - welches aber leider in fast allen UI-Frameworks so gelebt wird:
....
Und das sind jetzt schlechte Beispiele, weil .... ?
 
andy_m4 schrieb:
Und das sind jetzt schlechte Beispiele, weil .... ?

Das würde ich auch gerne mal wissen.

Laut seiner Aussage, müsste Finalspace der größte Feind von Java sein, da wird man gezwungen Vererbung und OO zu nutzen.
 
Finalspace schrieb:
Nope, man kann wirklich alles ohne Vererbung lösen!
Ein paar sehr schlechte Beispiele für Vererbung - welches aber leider in fast allen UI-Frameworks so gelebt wird

Einer der Gründe warum das vor allem bei UI gemacht wird, ist das Composite Pattern. Wie setzt man das Composite Pattern ohne Vererbung um?
 
Zuletzt bearbeitet:
Foochan schrieb:
Einer der Gründe warum das vor allem bei UI gemacht wird, ist das Composite Pattern. Wie setzt man das Composite Pattern ohne Vererbung um?

Ganz Einfach, man nutzt kein Composite Pattern ;-)
Es geht auch ohne und deutlich einfacher -> Immediate UI ohne den ganzen Retained State immer rumzuschleppen.

Oder man macht von mir aus ein Basiscontrol von dem jedes Control erbt, aber dann wars das.

Hades85 schrieb:
Das würde ich auch gerne mal wissen.

Laut seiner Aussage, müsste Finalspace der größte Feind von Java sein, da wird man gezwungen Vererbung und OO zu nutzen.

Ganz einfach, desto mehr Vererbung desto unübersichtlicher wird alles. Einfachere Strukturen sind leichter zu verstehen.
Ich bevorzuge Code den ich komplett von Anfang bis Ende durchsteppen kann und bei den meisten GUI Systemen kann man das nicht, da die so unglaublich komplex aufgebaut sind, da jedes Steuerlement immer seinen State speichern muss.

Und nein, ich habe Jahrelang mit Java gearbeitet und bin beruflich aktuell in .NET C#/C++ CLI/WPF und Delphi unterwegs.
Aber ich vermeide sofern es möglich ist, Abstraktion um jeden Preis - denn unnötige Abstraktion macht Code schwerer zu verstehen und zu warten, vor allem wenn mehrere Personen daran arbeiten.

Das mag für den ein oder anderen komisch klingen, ist aber schlicht und ergreifend das was ich seit über 20 Jahren mitgenommen habe.

Dazu eine kleine aktuelle Geschichte:
Ich komm in eine neue Firma (Großer Konzern, alles Windows Welt), bekomm zwei Projekte zugewiesen die ich weiterentwickeln soll:
- Eine ur-alt Monster-Anwendung in Delphi geschrieben mit sehr klarem und sauberen Code - unterteilt in ~50 dll´s, soll portiert werden ins neuste Delphi
- Eine .NET Anwendung die WCF (Windows Communication Foundation) und WPF nutzt und nichts anderes macht als eigene Programme über nen UNC Store zu aktualisieren, was nichts anderes ist als Verzeichnisse und Dateien zu kopieren

Die Delphiportierung war in nem Monat durch, da der Code sehr sauber strukturiert wurde und nur wenige Fremdkomponenten benutzt wurden - und das trotz Ansi > Unicode. Laufen tut das ding ast rein.

Dagegen die .NET Anwendung zu verbessern war unglaublich aufwendig und hat deutlich länger gedauert, da es auf MVVM aufbaut und man damit jeden Furz abstrahieren muss. Dazu hat WCF es um Faktor 10 erschwert, da debuggen schlichtweg nicht möglich war (Die Anwendung musste immer als Windows Service laufen, damit es Admin-Rechte hatte). Dazu kam noch, dass derjenige der die Anwendung ursprünglich gebaut hatte, keinen Plan von MVVM hatte und ich erstmal tonnenweise Zeug reparieren musste:

- Man darf keine Messageboxen oder irgendwelche UI Sachen aus dem Viewmodel aufrufen
- Ur-alter XAML Stil inkl. miesem handling von Commands
- Überall Klassen die keinen Sinn gemacht haben und alles nur unnötig verkompliziert haben
- Die Unit-Tests waren nutzlos, da hoffnungslos veraltet und teilweise sogar falsches Ergebnis erwartet wurde

MVVM war damals neu für mich, aber ein paar Stunden Googlen hatten mir gereicht um die Kernkonzepte zu verstehen und dann alles deutlich zu verbessern, zu vereinfachen aber sich dennoch an den MVVM Standard halten.

Ich programmiere seit 1995 mit Delphi 2 (Objektpascal) und bin von vorne rein in die OOP-Welt geworfen worden, was das komplette Gegenteil ist von vielen anderen die mit C oder Assembler angefangen hatten.

Und nein ich verteufele nicht OOP, aber hasse es wenn es unnötig zu excessive eingesetzt wird - vor allem um Code so zu verschleiern das man wirklich nichts mehr versteht:

- Klassen die eigentlich nur eine Methode haben
- Konstrukturen die nichts anderes machen als Felder initialisieren (C++)
- Exceptions everywhere -> Error codes ist doch nicht mehr State of the Art (Ein 100 er Exception Stack macht doch viel mehr Spaß zu debuggen, wenn der Datenbankpool vollgelaufen ist)
- Statische Klassen die Handler, Manager oder sonst wie heißen die mehr tun als sie zu angeben zu tun
- Getter und Setter obwohl eigentlich keine notwendig besteht für irgendwelche Sichtbarkeitsbeschränkungen
- C++ Bibliotheken die wild Speicher erzeugen und ich keinerlei Zugriff darauf habe
- Nutzlose Kommentare bei selbsterklärenden Funktionsnamen
- Code der in 100 Methoden ausgelagert wurde, obwohl kein Code mehrfach verwendet wird (Eine Methode soll ja nicht mehr wie 30 Zeilen haben -.-)
- Es ist kaum bis gar nicht möglich Schritt für Schritt das Programm von Oben nach Unten zu debuggen
- Exrem aufgeblähte C++ OOP API´s mit hunderten von Templates (Boost z.b.)
- Exceptions vor Asserts bevorzugen
 
Zuletzt bearbeitet:
Finalspace schrieb:
Es geht auch ohne und deutlich einfacher -> Immediate UI ohne den ganzen Retained State immer rumzuschleppen.
Was Du dabei verschweigst ist, dass Du die Probleme die man hat anders/selbst lösen musst. Was Du auf der einen Seite sparst musst Du halt auf der anderen Seite ausgeben.
Immediate UI lohnt also nur dann, wenn Du eigentlich gar nicht die Funktionalität brauchst, die Dir ein Retained-Mode-UI-Toolkit mitbringt.

Klar. Retained-Mode-UI neigt dazu, das die Sachen verteilt im Sourcecode rumfliegen. Aber genau dafür gibts ja Tools. Wenn man natürlich im Notepad codet ist Asche. :-)

Es bleibt also bestenfalls ein kommt darauf an.

Finalspace schrieb:
Ich bevorzuge Code den ich komplett von Anfang bis Ende durchsteppen kann
Hm. Erinnert mich stark an die BASIC-Interpreter früherer Tage. Mit Zeilennummern und so. :-)

Finalspace schrieb:
Ganz einfach, desto mehr Vererbung desto unübersichtlicher wird alles. Einfachere Strukturen sind leichter zu verstehen. []
und bei den meisten GUI Systemen kann man das nicht, da die so unglaublich komplex aufgebaut sind, da jedes Steuerlement immer seinen State speichern muss.
Also bei den von Dir aufgezählten Toolkits ist mir nur Swing bekannt. Und ich fand es ok. Soweit ich mich erinnern kann, kam man auch gar nicht viel mit Swing-Sourcecode in Kontakt. Im Gegenteil. Alles was Swing für einen gemacht hat, brauchte man gar nicht zu kennen. Das war dokumentiert und fertig. Man hatte nur den Source-Code vor sich, wo man eben GUI-Elemente verwendete.
Das wars. Deshalb verstehe ich nicht so ganz das Problem.

Finalspace schrieb:
Aber ich vermeide sofern es möglich ist, Abstraktion um jeden Preis - denn unnötige Abstraktion macht Code schwerer zu verstehen und zu warten, vor allem wenn mehrere Personen daran arbeiten.
Ja. Abstraktion der Abstraktion wegen macht sicher keinen Sinn. Und gerade Java (bzw. dessen Standardbibliotheken) ist ja durchaus voll davon, wenngleich sich die Situation an vielen Stellen schon gebessert hat.

Finalspace schrieb:
MVVM war damals neu für mich, aber ein paar Stunden Googlen hatten mir gereicht um die Kernkonzepte zu verstehen und dann alles deutlich zu verbessern, zu vereinfachen aber sich dennoch an den MVVM Standard halten.
Ich versteh jetzt grad den bezug zu UI-Frameworks nicht. Du hast lediglich ein Projekt von nem guten Programmierer und nem schlechten Programmierer verglichen. Was soll uns das jetzt sagen?

Finalspace schrieb:
Und nein ich verteufele nicht OOP, aber hasse es wenn es unnötig zu excessive eingesetzt wird
Man muss dazu sagen, dass Java (und noch weniger C++) gute Beispiele für ne gelungene OOP-Umsetzung sind. Da ist schon von der Sprach-Seite her viel kaputt. Das wirkt sich dann natürlich auch auf alles andere aus.
Unwidersprochen dessen, das man auch da natürlich noch eins draufsetzen kann.
 
Inwiefern ist OOP in C++ schlecht umgesetzt?


- Klassen die eigentlich nur eine Methode haben
​Was denken die sich nur mit dem Command pattern, müssen ja völlig übergeschnappt sein.
- Konstrukturen die nichts anderes machen als Felder initialisieren (C++)
​Was ist daran so schlecht?
Code der in 100 Methoden ausgelagert wurde, obwohl kein Code mehrfach verwendet wird (Eine Methode soll ja nicht mehr wie 30 Zeilen haben -.-)
​Oft geht es nicht nur um DRY, sondern auch darum Komplexität zu verbergen um ggf. ellenlangen Code kurz und prägnant zusammenzufassen und überblicken zu können.
 
Zuletzt bearbeitet:
Ich weiß nicht so recht: Der Artikel zeigt ein Beispiel in dem Inheritance von Anfang an nicht hätte verwendet werden sollen, weil - wie von
NullPointer angesprochen - das Liskovs Substitutionsprinzip verletzt wird (ein stack ist kein Array), überschreibt dann auch noch nicht einmal alle relevanten methoden und begründet dann damit, dass extens gefährlich ist. Unabhängig davon ob man jetzt der Aussage generell zustimmt oder nicht, finde ich die Argumentation teilweise etwas schwach.

Persönlich bin ich fast nur in C++ unterwegs und da kommen Klassenhierarchien gefühlt ohnehin nicht so häufig vor (von GUI-Frameworks mal abgesehen), aber wenns passt - warum nich?t Insbesondere Mixins / CRTPs finde ich manchmal recht praktisch. Außerdem kommts auch drauf an, ob man versucht eine generische und erweiterbare Klassenhierarchie mit zig abgeleiteten Klassen zu erschaffen oder ob man damit gezielt ein lokales Problem löst.
 
Zuletzt bearbeitet:
andy_m4 schrieb:
Was Du dabei verschweigst ist, dass Du die Probleme die man hat anders/selbst lösen musst. Was Du auf der einen Seite sparst musst Du halt auf der anderen Seite ausgeben.
Immediate UI lohnt also nur dann, wenn Du eigentlich gar nicht die Funktionalität brauchst, die Dir ein Retained-Mode-UI-Toolkit mitbringt.

Klar. Retained-Mode-UI neigt dazu, das die Sachen verteilt im Sourcecode rumfliegen. Aber genau dafür gibts ja Tools. Wenn man natürlich im Notepad codet ist Asche. :-)

Es bleibt also bestenfalls ein kommt darauf an.

Das stimmt das man in Immediate UI´s sich komplett um das Handling selber kümmern muss, was ich aber sehr gut finde weil dann entscheide ich, was mein UI kann und woher die Daten für kommen. Vor allem habe ich wenig bis gar keinen Initialisierungsaufwand.

Achja für diejenigen die dieses Konzept nicht kennen:
Immediate Mode Graphical User Interfaces

Und ja man kann damit auch sehr komplexe und aufwendige UI´s bauen und ist nicht nur für die Spielentwicklung interessant.

andy_m4 schrieb:
Hm. Erinnert mich stark an die BASIC-Interpreter früherer Tage. Mit Zeilennummern und so. :-)

Code wird nun mal Sequentiell ausgeführt, auch Multithreaded-Code - das hat sich in 50 Jahren nicht geändert und wird sich so schnell auch nicht ändern. Und ja CPU-Instruktionen werden auf modernen CPU´s teils parallel ausgeführt, die Anfrage und das Ergebnis allerdings bleibt allerdings immer Sequentiel.
Wenn C = A * B ausgeführt wird, dann ist in der nächsten Zeile das Ergebnis für C im Register verfügbar.

Und dank Visual Studio kann man auch Multithreaded-Code bequem Zeile für Zeile durchgehen.

andy_m4 schrieb:
Also bei den von Dir aufgezählten Toolkits ist mir nur Swing bekannt. Und ich fand es ok. Soweit ich mich erinnern kann, kam man auch gar nicht viel mit Swing-Sourcecode in Kontakt. Im Gegenteil. Alles was Swing für einen gemacht hat, brauchte man gar nicht zu kennen. Das war dokumentiert und fertig. Man hatte nur den Source-Code vor sich, wo man eben GUI-Elemente verwendete.
Das wars. Deshalb verstehe ich nicht so ganz das Problem.

Das Problem kommt, sobald du was benutzt was nicht vernünftig dokumentiert ist, muss man mehr oder weniger raten was das jetzt tut oder warum es nicht funktioniert.
Einfach mal reinsteppen und zu gucken was da fehlt ist einfach nicht möglich.

andy_m4 schrieb:
Ich versteh jetzt grad den bezug zu UI-Frameworks nicht. Du hast lediglich ein Projekt von nem guten Programmierer und nem schlechten Programmierer verglichen. Was soll uns das jetzt sagen?

Ja das war nicht wirklich ein gutes Beispiel, allerdings war der Programmierer der .NET Anwendung jetzt nicht schlecht - hat aber manche Sachen unnötig Abstrakt gelöst,
während die Delphi Anwendung den Code direkt im UI hatte, ohne Interfaces, ohne Klassen die irgendwas Handeln oder Managen...
Und hätte man anstatt WCF simples TCP verwendet, was ein einer einzigen Klasse gekapselt gewesen wäre inkl. simpler Client-Server Komminukation, dann wäre es viel verständlicher und wartbarer gewesen.

andy_m4 schrieb:
Man muss dazu sagen, dass Java (und noch weniger C++) gute Beispiele für ne gelungene OOP-Umsetzung sind. Da ist schon von der Sprach-Seite her viel kaputt. Das wirkt sich dann natürlich auch auf alles andere aus.
Unwidersprochen dessen, das man auch da natürlich noch eins draufsetzen kann.

Ja C++ ist ein sehr gutes Beispiel für schlechtes OOP:

- Es gibt kein Konzept von richtigen Interfaces in C++, das wird alles über Virtuelle Funktionen gelöst
- Templates sind eine Qual, vor allem wenn Vererbt
- Klassendeklaration ist schlicht und erreifend veraltet und unnötig -> Es geht auch ohne, siehe Java, C# etc.
- Keine Metaprogrammierung oder Reflection (RTTI ist kein vollständiges Reflection!)
- Keine Properties, allerdings sind diese auch in anderen Sprachen grenzwertig da man nicht immer Sicher ist das nur ein get und set machen
- Es gibt noch andere Gründe, aber im Moment fällt mir nicht mehr ein

Von allen Sprachen die ich so kenne ist C# die Sprache, die OOP am besten umsetzt - allerdings wird das auch zu excessiv gelebt für meinen Geschmack :-(

Ich verwende immer je nach Anwendungsfall das Verfahren was am einfachsten und besten zu warten ist -> Bevorzugt: Simple Methoden wo alle Parameter übergeben werden die nur das anfassen was an Parametern reinkommen und wenns zuviele werden, dann wird nen Context drum herum gebaut - fertig.
 
Zuletzt bearbeitet:
Finalspace schrieb:
Ja das war nicht wirklich ein gutes Beispiel, allerdings war der Programmierer der .NET Anwendung jetzt nicht schlecht - hat aber manche Sachen unnötig Abstrakt gelöst, während die Delphi Anwendung den Code direkt im UI hatte, ohne Interfaces, ohne Klassen die irgendwas Handeln oder Managen...
Code in der GUI war und ist aber immer ein Problem. Genau deshalb gibt es Patterns wie MVC und MVVM: Um die Logik (und damit meine sowohl Geschäfts- als auch GUI-Logik) und von der GUI zu trennen.
Vielleicht verstehe ich dich falsch, aber wie z. B. bei Windows Forms den ganzen Code in den Code-Behind der GUI zu packen ist bei jeder größeren GUI fürchterlich schlecht wartbar. Von der fehlenden Testbarkeit mal abgesehen.
Mit richtig gemachtem MVVM (wobei auch nicht DAS MVVM gibt) kann man (auf Kosten von manchmal etwas mehr Code) sehr saubere und auch testbare GUI erstellen.

Finalspace schrieb:
Das Problem kommt, sobald du was benutzt was nicht vernünftig dokumentiert ist, muss man mehr oder weniger raten was das jetzt tut oder warum es nicht funktioniert.
Einfach mal reinsteppen und zu gucken was da fehlt ist einfach nicht möglich.
Konsequenterweise müsste man daraus folgern, dass man alles selbst schreibt.
Gerade solche aus dem "Not-invented-here-Syndrom" entstanden Dinge sind dann aber meist noch schlechter Dokumentiert (vielleicht bei dir anders) und verursachen zusätzlichen Wartungsaufwand.
Absehen davon müssen sich neue Teammitglieder erst in z. B. das eigene GUI-Framework einarbeiten statt z. B. bestehende WPF-Kenntnisse nutzen zu können.

Finalspace schrieb:
Und hätte man anstatt WCF simples TCP verwendet, was ein einer einzigen Klasse gekapselt gewesen wäre inkl. simpler Client-Server Komminukation, dann wäre es viel verständlicher und wartbarer gewesen.
Und schon hat man ein neues proprietäres Datenformat geschaffen. Will ich mit deiner Anwendung kommunizieren darf ich erst dein Datenformat lernen und eine Parser dafür schreiben.
Auch wenn die zugegeben nicht das schlankeste Framework ist, erlaubt sie doch Kommunikation in standardisierten Formaten (SOAP, REST mit XML oder JSON) mit relativ wenig Aufwand.
Mir ist ein ordentlich gebauter WCF- oder besser noch ASP.NET MVC Web API-Service hundertmal lieber als "nacktes" TCP bei dem ich mich erst ums parsing kümmern muss.
Außerdem gibt's zu diesen Frameworks massenhaft Ressourcen und Entwickler die dich damit auskennen. Dein "Framework" kennst erstmal nur du und deine aktuellen Kollegen.

Wenn man zeit- und/oder bandbreitenkritische Kommunikation hat, sieht das alles etwas anders aus, aber für die meisten Fälle würde ich hier auf Standard-Frameworks setzen.

Finalspace schrieb:
Bevorzugt: Simple Methoden wo alle Parameter übergeben werden die nur das anfassen was an Parametern reinkommen und wenns zuviele werden, dann wird nen Context drum herum gebaut - fertig.
Das bietet sich manchmal an (z. B. bei Rekursionen) aber zum Standard würde ich das nicht erheben wollen.
Wenn ich in einer Methode weiter unten einen neuen Parameter brauche, muss ich potentiell eine große Menge von Methoden anpassen, damit der Parameter "durchgeschleift" wird. Genau das kann man mit OOP glücklicherweise verhindern.
 
Zuletzt bearbeitet: (Zweiter Absatz ergänzt.)
TheCadillacMan schrieb:
Das bietet sich manchmal an (z. B. bei Rekursionen) aber zum Standard würde ich das nicht erheben wollen.
Wenn ich in einer Methode weiter unten einen neuen Parameter brauche, muss ich potentiell eine große Menge von Methoden anpassen, damit der Parameter "durchgeschleift" wird. Genau das kann man mit OOP glücklicherweise verhindern.

Also ob ich jetzt ne Klasse habe, die alles kapselt was ich brauche oder einem Context ist für mich kein Unterschied - nur das der Context keine Logik enthält und nur die Instanzen als Public enthält.

Aber selbst wenn, was ist daran schlimm in ein paar stellen die Methoden anzupassen? Ist doch kein Problem, gibt ja keine Größenbeschränkung oder so, bzw. der Stack reicht locker dafür aus.

Aber man sollte hier nicht weiter abschweifen, denke wir sind uns aber alle einig das Vererbung grundsätzlich okay ist, sofern nicht übertrieben und hilft das eigentliche Problem zu lösen. Man sollte halt versuchen die Hierarchie so flach wie möglich zu halten.
 
The Ripper schrieb:
Inwiefern ist OOP in C++ schlecht umgesetzt?
OOP wurde lediglich drangeflanscht. Und das merkst Du halt an vielen Stellen. Außerdem wurden viele Dinge weggelassen die OOP ausmachen (Reflection, echte Polymophie etc.). Aus Performance-Gründen. Das kann man durchaus auch als Vorteil sehen. Aber aus OOP-Sicht ist das eben weniger schön.
Ergänzung ()

Finalspace schrieb:
Das stimmt das man in Immediate UI´s sich komplett um das Handling selber kümmern muss, was ich aber sehr gut finde weil dann entscheide ich, was mein UI kann und woher die Daten für kommen.
Das kannst Du auch bei einem klassischen Toolkit haben. Gerade Swing kennt z.B. Modellklassen die Du dafür benutzen kannst um Deine Daten aus einer Datenbank, Datei, whatever zu holen.

Finalspace schrieb:
Vor allem habe ich wenig bis gar keinen Initialisierungsaufwand.
Wie gesagt. Kommt alles auch immer ein wenig auf den Einsatzzweck an, wann so etwas sinnvoll ist und wann nicht.

Finalspace schrieb:
Und ja man kann damit auch sehr komplexe und aufwendige UI´s bauen und ist nicht nur für die Spielentwicklung interessant.
Das ist ja nicht die Frage. Komplexe GUIs kann ich auch in Assembler bauen. Die Frage ist, ob ich das will.
Und manchmal kann ich selbst das wollen. Beispielsweise auf leistungsschwacher Hardware. Wie gesagt. Kommt alles immer sehr auf den Zweck an.

Finalspace schrieb:
Code wird nun mal Sequentiell ausgeführt, auch Multithreaded-Code - das hat sich in 50 Jahren nicht geändert und wird sich so schnell auch nicht ändern.
Das ist bei Green-Threads (Java-Sprech) so, aber nicht bei native-threads die auf mehrere CPU-Kerne verteilt werden.

siehe dazu: https://de.wikipedia.org/wiki/Thread_(Informatik)

Finalspace schrieb:
Und ja CPU-Instruktionen werden auf modernen CPU´s teils parallel ausgeführt,
Sofern sie auf mehrere Kerne aufgeteilt sind werden sie parallel ausgeführt.

Finalspace schrieb:
die Anfrage und das Ergebnis allerdings bleibt allerdings immer Sequentiel.
Wenn C = A * B ausgeführt wird, dann ist in der nächsten Zeile das Ergebnis für C im Register verfügbar.
Das gilt für SMT a-ka Hyerthreading. Sind die Threads auf mehrere Kerne verteilt hast Du natürlich auch alle Register doppelt.

Sollte man eigentlich alles wissen, wenn man seit 1995 programmiert. ;-)

Das Problem ist, dass Multithreaded-Programmierung nicht unbedingt trivial ist und deshalb noch teilweise sehr verhalten eingesetzt wird. Auch GUI-Toolkits können nicht unbedingt immer damit umgehen, wenn ein zweiter Thread ihnen ins Handwerk pfuscht.

Finalspace schrieb:
Und dank Visual Studio kann man auch Multithreaded-Code bequem Zeile für Zeile durchgehen.
Ich kenn jetzt Visual Studio nicht, aber entweder unterbricht der während einer Debugging-Session die jeweils anderen Threads oder Du hast eine Applikation gedebugt, die green-threaded ist.

Finalspace schrieb:
  • Es gibt kein Konzept von richtigen Interfaces in C++, das wird alles über Virtuelle Funktionen gelöst
Ähm. virtuelle Methoden sind der Gegenentwurf zum late-binding. Also ein Polymorphismus-Feature.
Den Ersatz von Interfaces würde ich bei C++ eher in der Mehrfachvererbung sehen.

Finalspace schrieb:
  • Klassendeklaration ist schlicht und erreifend veraltet und unnötig
Klassen musst Du auch in Java deklarieren. Oder was meinst Du mit Klassendeklaration ?

Finalspace schrieb:
  • Keine Properties, allerdings sind diese auch in anderen Sprachen grenzwertig da man nicht immer Sicher ist das nur ein get und set machen
Genau. Properties verschleiern so ein bisschen, was da wirklich passiert. Also eigentlich genau das, was Du nicht magst. :-)

Finalspace schrieb:
  • Keine Metaprogrammierung
Templates sind für Metaprogrammierung. Was Du vermutlich meinst, ist Metaprogrammierung zur Laufzeit.

Finalspace schrieb:
Von allen Sprachen die ich so kenne ist C# die Sprache, die OOP am besten umsetzt
Für meinen Geschmack ist nach wie vor Smalltalk die Sprache die Objektorientierung am besten umsetzt. Bei C# fängts ja schon damit an, dass Du primitive Datentypen hast die eben keine Objekte sind.
 
Zurück
Oben