OOP: attribute nur über methoden ändern



  • Ich hab mal in einem Buch gelesen, dass man gemäß OOP die Attribute einer Klasse nur über Methoden ändern "soll".

    Warum?
    Kann doch auch direkt das Attribut überschreiben self.hoehe = 4 ?
    Mir sammeln sich sonst da zu viele "unnötoge" Methoden an?!



  • Es verbessert die Wartbarkeit und Anpassungsfähigkeit der Klasse, wenn du die wichtigen Punkte zentral kapselst. Klar wird irgendeine Methode doch die Attribute direkt anfassen - aber es ist doch besser wenn du nur eine Stelle ändern mußt, weil dir auffällt, daß die Höhe auch durch die Koordinaten von Ober- und Unterkante ausgedrückt werden kann.



  • Wenn du eine Klasse nur dazu verwendest, um ausschließlich Daten zusammenzuhalten, als Konstruktorargument z.B., dann mach Variablen public und keine Methoden. Sobald die Klassen aber irgendwas "können" sollen, sollten sie immer private sein, der Kapselung wegen.



  • 314159265358979 schrieb:

    Wenn du eine Klasse nur dazu verwendest, um ausschließlich Daten zusammenzuhalten, als Konstruktorargument z.B., dann mach Variablen public und keine Methoden. Sobald die Klassen aber irgendwas "können" sollen, sollten sie immer private sein, der Kapselung wegen.

    Im Prinzip mag dies ein Argument für öffentliche Variablen sein, ich habe in der Vergangenheit aber schon häufiger bemerkt, das irgendwann doch eine kleine Zusatzlogik beim Setzen nötig wurde, oder ein Lesevorgang nachträglich seine Daten von anderer Stelle als der Klasse (oder berechnet) liefert.

    Selbst bei einer einfachen Datenklasse verwende ich daher je nach Sprache Getter/Setter oder Properties (Letztere ziehe ich wegen den üblichen Standardfällen in der Regel vor, vor allem wenn eine Kurzschreibweise dadurch möglich ist, wie in C# [z.B. "public String Name { get; set; };" ].



  • In C# Properties, ja. Aber in Sprachen, die sowas nicht haben, public Variablen.



  • 314159265358979 schrieb:

    In C# Properties, ja. Aber in Sprachen, die sowas nicht haben, public Variablen.

    Und dann darf man das gesamte Projekt überarbeiten, falls die Schnittstelle etwas geändert werden muss (Beispiel: bestimmte Attribute auf LazyLoad umstellen). Dann sind mit Setter/Getter lieber, selbst für "reine" Datenklassen.



  • Mich würde mal interessieren, wieviele Leute dieses Std-Getter-Argument nur stumpf einem Buch nachplappern und wieviele wirklich schon damit auf die Schnauze gefallen sind.
    Ich unterstell dir nichts, asc, sondern glaube dir das gerne, aber ich kann von mir sagen, dass ich in den mittlerweile ca 15 Jahren OOP immer mal auf Getter verzichtet habe, wenn es für mich Sinn machte und ich das nie nachträglich bereut habe.
    Und wenn es dann irgendwann nach 20 Jahren oder so doch mal passieren würde, dann könnte ich damit auch leben.



  • Jockelx schrieb:

    Ich unterstell dir nichts, asc, sondern glaube dir das gerne, aber ich kann von mir sagen, dass ich in den mittlerweile ca 15 Jahren OOP immer mal auf Getter verzichtet habe, wenn es für mich Sinn machte und ich das nie nachträglich bereut habe.

    Ich arbeite leider in der Regel mit IDEs die kein sinnvolles Refactoring unterstützen, und hatte schon in mehreren Projekten den Fall, dass das Verhalten nachträglich geändert werden musste.

    Gut, dies ist vor allen in "historisch" gewachsenen Projekten passiert, und teilweise noch mit anderen Nebenproblemen (z.B. hatte ein Vorgänger in ein Projekt nahezu ohne Ausnahme alle Variablen public und meist auch static deklariert, und es war später sehr aufwändig dies zu verändern).

    Mit einer IDE die wirklich sauber Refactoring unterstützt sieht es tatsächlich anders aus (oder zumindest Erleichtert es die Änderung wenn nötig).

    Jockelx schrieb:

    Und wenn es dann irgendwann nach 20 Jahren oder so doch mal passieren würde, dann könnte ich damit auch leben.

    Mich hat es schon viele Mannwochen gekostet, daher sehe ich das Thema etwas anders. Leider kann man sich die Werkzeuge für ein Projekt aber nicht aussuchen, und muss mit den Mitteln leben, die einem gestellt werden.



  • Wartbarkeit hin oder her, es widerspricht schlicht dem OOP-Prinzip der Datenkapselung. Daß man selbst riesige Projekte mit 1e9+ LOC auch ohne getter/setter hinbekommen kann, bezweifelt niemand - schließlich kann man auch auf alle anderen Annahmlichkeiten der OOP freiwillig verzichten. Die Frage ist nur: wozu?



  • fragenase schrieb:

    Ich hab mal in einem Buch gelesen, dass man gemäß OOP die Attribute einer Klasse nur über Methoden ändern "soll".

    Warum?
    Kann doch auch direkt das Attribut überschreiben self.hoehe = 4 ?
    Mir sammeln sich sonst da zu viele "unnötoge" Methoden an?!

    Einfach gesagt: Setter und Getter erlauben Dir die interne Repräsentation der Daten zu verändern, ohne dass sich dadurch das Verhalten der Klasse nach außen verändert. Das gilt sogar für einfache Klassen zur Datenhaltung.
    Einfaches Beispiel: Du hast eine Klasse für komplexe Zahlen und änderst die interne Repräsentation der Zahl von der kartesischen Form in Polarkoordinatendarstellung. Bei öffentlichen Variablen hättest Du nun ein Problem mit Code der auf re und im zugreift, weil es diese Attribute nicht mehr gibt. Bei Settern und Gettern würde man die Änderung gar nicht bemerken.



  • Jockelx schrieb:

    Mich würde mal interessieren, wieviele Leute dieses Std-Getter-Argument nur stumpf einem Buch nachplappern und wieviele wirklich schon damit auf die Schnauze gefallen sind.

    Noch ein paar Gegenfragen:
    Hast du noch nie Fälle erlebt...
    - bei denen Daten in einem bestimmten Wertebereich liegen müssen?
    (Dies kann man z.B. in Settern sehr gut abfangen)
    - bei denen Daten nur in bestimmten Konstellationen gültig sind?
    (Dann sind zwar Getter okay, aber es würde nur ein kombiniertes "Setter" [Oder
    wie man die Methode auch immer nennen mag] Sinn machen).

    Und ja, wenn es um grundlegende Datenkonsistenz geht, pack ich dies auch in Datenklassen (Selbst wenn ich der Klasse ansonsten keine Logik spendiere).

    Und da bestimmte Beziehungen und Bereichsprüfungen ggf. erst im Nachhinein bekannt sind, habe ich mit Gettern/Settern den Vorteil, das ich die Schnittstelle in der Regel nicht ändern muss. Und bei Verstößen gegen Wertebereichen kann ich wenigstens im Debugger sicher herausfinden, von welcher Stelle die falschen Werte gesetzt wurden (und dort nach Fehlern suchen).



  • Deine Gegenfragen haben mit der bisherigen Diskussion aber wenig zu tun.
    Niemand stellt getter/setter generell in Frage.

    Richtig formuliert wären die Fragen:

    Hast du noch nie Fälle erlebt...
    - bei denen Daten in einem bestimmten Wertebereich liegen müssen, du dir aber fälschlicherweise vorher absolut sicher warst, dass das nicht benötigt wird?

    - bei denen Daten nur in bestimmten Konstellationen gültig sind, du dir aber fälschlicherweise vorher absolut sicher warst, dass das nicht so sein wird?

    Beides kann ich verneinen. Hab ich noch nie erlebt.



  • Jockelx schrieb:

    Deine Gegenfragen haben mit der bisherigen Diskussion aber wenig zu tun.
    Niemand stellt getter/setter generell in Frage.

    Richtig formuliert wären die Fragen:

    Hast du noch nie Fälle erlebt...
    - bei denen Daten in einem bestimmten Wertebereich liegen müssen, du dir aber fälschlicherweise vorher absolut sicher warst, dass das nicht benötigt wird?

    - bei denen Daten nur in bestimmten Konstellationen gültig sind, du dir aber fälschlicherweise vorher absolut sicher warst, dass das nicht so sein wird?

    Beides kann ich verneinen. Hab ich noch nie erlebt.

    Das ist auch nicht der Hauptzweck der Geschichte. Der Hauptzweck ist, dass sich das sich die interne Repräsentation bei gleichbleibendem Interface ändern darf, ohne dass anderer Code geändert werden muss. Und ja, das kommt ziemlich häufig bei mir vor.



  • Jockelx schrieb:

    Deine Gegenfragen haben mit der bisherigen Diskussion aber wenig zu tun.

    Sie haben durchaus etwas damit zu tun (siehe auch unten).

    Jockelx schrieb:

    Beides kann ich verneinen. Hab ich noch nie erlebt.

    Dann könnte es vielleicht sein, das du weder mit alten ("historisch gewachsenen") Code zu tun gehabt hast, oder noch kein Projekt mit einer sehr langen Lebensdauer erlebt hast - dort ändern sich Anforderungen durchaus im Laufe der Zeit, oder ein Entwickler/Tester bemerkt etwas, das ein Anderer außer acht gelassen hat.

    Genauso habe ich (noch relativ aktuell) einen Fall erlebt wo bestimmte Daten sehr selten benötigt wurden sind, aber viel Einleseaufwand bedeutet haben. Anfangs waren unsere Kunden tendenziell kleine Kunden, so das sich der Leseaufwand noch im Rahmen gehalten hat, nun haben wir aber auch größere Einrichtungen, und da kann es je nach Datenbank schon wesentliche Unterschiede machen.

    Auch wenn ich kein Freund von Compilererweiterung bin, war ich hier mehr als froh das es als Property decklariert war, so das ich die Eigenschaft mittels LazyLoad bei Bedarf nachlade, ohne die Schnittstelle ändern zu müssen. Wäre es eine öffentliche Variable gewesen, wäre dies nicht ohne viel mehraufwand möglich gewesen.


Anmelden zum Antworten