"Getter" und "Setter" - Ja oder nein?



  • Ich hab mal wieder eine frage, auf die ich von allen seiten seit... joa eigentlich schon immer 😃 verschiedene meinungen höre.

    Was sind vorteile und nachteile wenn man "getter" und "setter" funktionen für den zugriff auf memebervariablen verwendet, bzw. wann sollte man sie verwenden und wann nicht.
    Verwendet ihr derartige funktionen? Wenn ja warum?

    meine programme laufen größtenteils singlethreaded, also das thema kann erstmal unbeachtet bleiben 😉

    PS: ich weiß, das ist nur so eins der vielen kleinen (unwichtigen) details eines programms, aber ich möchte das jetzt einmal geklärt haben 🙂



  • Saubere Schnittstellen bedingen getter/setter.
    Für Wartbarkeit wie z.B. Debugging sind getter/setter per se besser geeignet als sich auf irgendwelche IDE Features diesbezüglich zu verlassen.
    Performanzgewinne durch Einsparen von getter/setter sind Aberglaube.



  • also die schreibarbeit lohnt sich 👍

    besser geeignet als sich auf irgendwelche IDE Features diesbezüglich zu verlassen

    ...das war auch der grund warum ich es bis jetzt so gemacht habe



  • In den meisten Fällen lohnt sich das. Der Nachteil ist die größere Schreibarbeit, insbesondere wenn man auf Elemente der Klasse/Struktur später zugreift und die Verschachtelungstiefe hoch ist.

    Die Vorteile liegen darin, dass man keinen direkten Zugriff auf die Attribute hat, sondern gekapselt. Dadurch kann man bei Bedarf Set/Get auch etwas zurückgeben lassen, was nicht 1:1 ein Attribut ist. Beispielsweise könnte eine Klasse einige Attribute halten und dazu Getter anbieten. Später merkt man jedoch, dass sich ein Attribut aus den anderen berechnen lassen kann. Jetzt kann man das Attribut einfach löschen und den Getter ändern ohne sonst irgendwelchen Code anfassen zu müssen.

    Hätte man hier einen direkten Zugriff auf das Attribut gehabt, so hätte man den Code überall dort ändern müssen, wo der Zugriff erfolgt wäre.

    Das gilt übrigens für private Attribute, auf die man über andere Klassen/Funktionen zugreift, wie auch für private Attribute, auf die von Unterklassen zugegriffen werden soll; die sollten auch nicht protected sein, da hier dieselbe Kapselungsargumentation gilt.

    Bis auf das Beispiel oben fällt mir jedoch gerade kein wesentlicher Vorteil ein. Wenn klar ist, dass eine Struktur nur bloße Daten hat (und daher eben auch eine Struktur und nicht Klasse ist, was diese Semantik bereits andeutet), dann kann man sich die Getter/Setter wohl auch sparen. Üblich ist das bei Strukturen, die z.B. als Rückgabe- oder als Parameterübergabe-Typen dienen.

    Umso länger ich darüber nachdenke, umso weniger trivial oder pauschal beantwortbar finde ich die Frage. Gab auch Mal eine umfangreiche Diskussion dazu, bei der - ich glaube - knivil für etwas weniger Getter/Setter (nicht keine!) plädiert hatte.



  • Problematisch wird es, wenn man präventiv für jede Membervariable ein get/set-Paar einbaut, weil man ja auf die entsprechende Variable mal zugreifen könnte. Man sollte sich eher überlegen, welche Eigenschaften einer Klasse nach aussen relevant sind (Schnittstelle) und wie man auf diese zugreifen möchte. Teilweise will man nämlich gar nicht den Wert direkt setzen, sondern ihn auf eine bestimmte Art verändern. Oder man will nur lesen. Oder gar nichts...

    Zu viele Getter/Setter wirken sich negativ auf Kapselung aus, da man der Implementierung weniger Freiheiten lässt (sie muss bestimmte Werte anbieten, obwohl diese vielleicht nur für eine spezifische Implementierung, und nicht für die Funktionalität der Klasse an sich notwendig sind). Die Alternative sind dabei nicht public -Variablen, sondern besser ausgedachte Modifiziererfunktionen.



  • Getter und Setter brechen die Kapselung. Wann immer du meinst, einen Getter oder Setter zu brauchen, solltest du darüber nachdenken, was die Variable eigentlich in der Klasse verloren hat.



  • Getter/Setter sollte man Grundsätzlich immer dann einsetzen wenn man nur eins von beidem braucht, also zB nur Lesezugriff, oder wenn der Zugriff eine direkte Nebenwirkung hat, Ausrechnen von Werten oder Weitergabe der Änderung. Hier sollte man aber auch nur das nutzen was man wirklich braucht, pauschal alles anzubieten artet schnell aus.

    Wo ich Getter/Setter Grundsätzlich nicht einsetze sind Strukturen und Reine Arbeitsklassen die Daten mit ein paar operationen verbinden, zB 2D / 3D Vektoren, Brüche usw. Dort haben änderungen keine Auswirkung und die Klasse ist rein dazu gebaut diese Daten oft zu ändern.



  • Zu beachten ist, daß einige Typen ihre Attribute nicht oder nur sehr schwer nachträglich ändern können. Einige? Naja, viele, fast alle.
    Siehe http://www.c-plusplus.net/forum/313498-64
    Man beachte:
    Die Person wird nie ihren Namen ändern. (2 Setter weg).
    Das Alter wird besser nicht gespeicher, sondern der Geburtstag. (1 Setter weg).
    Ups, alle Setter weg.
    Was muss intern passieren bei

    if(pImage->getFormat()=="BMP") 
       pImage->setFormat("BMP");
    

    ?



  • Xebov schrieb:

    Wo ich Getter/Setter Grundsätzlich nicht einsetze sind Strukturen und Reine Arbeitsklassen die Daten mit ein paar operationen verbinden, zB 2D / 3D Vektoren, Brüche usw. Dort haben änderungen keine Auswirkung und die Klasse ist rein dazu gebaut diese Daten oft zu ändern.

    Du könntest leicher jagen, welches taube Nüßchen Dir eine 0 in den Nenner geschrieben hat.



  • Reine "Datenhalter" Klassen, die keine Invarianten etc. haben, bekommen bei mir einfach öffentliche Member.
    Also z.B. die erwähnten 2D/3D-Vektoren, ne Rect-Klasse etc.
    Genau so diverse Parameters-Klassen die zur Vermeidung von Funktionen mit mehr als 2-3 Parametern verwendet werden.

    Dadurch bleiben dann kaum noch Klassen übrig, die nur triviale return x Getter bzw. x = value Setter haben.
    Meist macht zumindest der Setter irgendwas zusätzlich.



  • dot schrieb:

    Getter und Setter brechen die Kapselung. Wann immer du meinst, einen Getter oder Setter zu brauchen, solltest du darüber nachdenken, was die Variable eigentlich in der Klasse verloren hat.

    Das ist ein Statement, das nur mit eine sehr engen Definition von "Getter" bzw. "Setter" Sinn macht.
    Bevor man sowas behauptet, sollte mal also besser erklären was man mit "Getter" und "Setter" meint.

    Beispielsweise wird quasi jedes Widget einer GUI Library einen "Setter" für die Position haben. Ob der nun "SetPosition" oder "Move" heisst ist dabei mMn. irrelevant. Das heisst aber nicht dass dabei die Kapselung gebrochen wurde.
    Natürlich macht der SetPosition Setter dabei mehr als nur pos = value , und ist daher laut der für das von dir abgegebene Statement nötigen Definition vermutlich kein Setter mehr.



  • hustbaer schrieb:

    Bevor man sowas behauptet, sollte mal also besser erklären was man mit "Getter" und "Setter" meint.

    Damit meine ich Funktionen, die internen Zustand nach außen propagieren. Eine klare Grenze zu ziehen ist schwer, aber imo sollte man diese eher eng ansetzen, da ansonsten am Ende jede Methode als Getter oder Setter zu verstehen wäre...

    hustbaer schrieb:

    Beispielsweise wird quasi jedes Widget einer GUI Library einen "Setter" für die Position haben. Ob der nun "SetPosition" oder "Move" heisst ist dabei mMn. irrelevant. Das heisst aber nicht dass dabei die Kapselung gebrochen wurde.

    Das hängt wohl stark vom Design der UI Library ab. Bei mir ist die Position eines Widget z.B. kein Attribut des Widget, sondern wird vom Container des Widget bestimmt, welcher sich um das Layout kümmert... 😉



  • dot schrieb:

    Getter und Setter brechen die Kapselung. Wann immer du meinst, einen Getter oder Setter zu brauchen, solltest du darüber nachdenken, was die Variable eigentlich in der Klasse verloren hat.

    Das ist doch nur ein krampfhafter versuch etwas "besser" zu machen, obwohl es nicht sein muss. Wenn ich z.B. ein CAD Programm habe und die Objekte (Kurven/Flächen) haben Namen die in verschiedenen GUI-Elementen angezeigt/umbenannt werden können, warum sollen die dann kein get/setName haben? Was würdest du machen? Warum ist das dann besser?



  • a35sw4ed5rf6t7gz8h schrieb:

    dot schrieb:

    Getter und Setter brechen die Kapselung. Wann immer du meinst, einen Getter oder Setter zu brauchen, solltest du darüber nachdenken, was die Variable eigentlich in der Klasse verloren hat.

    Das ist doch nur ein krampfhafter versuch etwas "besser" zu machen, obwohl es nicht sein muss. Wenn ich z.B. ein CAD Programm habe und die Objekte (Kurven/Flächen) haben Namen die in verschiedenen GUI-Elementen angezeigt/umbenannt werden können, warum sollen die dann kein get/setName haben? Was würdest du machen? Warum ist das dann besser?

    Was genau ist der Grund, wieso der Name deiner Meinung nach Teil einer Kurve oder Fläche sein sollte? Imo ist der Name etwas, über das eine bestimmte Instanz einer Kurve oder Fläche von der Anwendung identifiziert werden kann. Ein Name ist aber imo nicht Teil des Konzepts einer Kurve oder Fläche. Folgedessen sollte der Name auch nicht Attribut der Klasse Kurve bzw. Fläche sein, sondern die Anwendung eine Map haben, die Namen auf Instanzen abbildet...



  • dot schrieb:

    a35sw4ed5rf6t7gz8h schrieb:

    dot schrieb:

    Getter und Setter brechen die Kapselung. Wann immer du meinst, einen Getter oder Setter zu brauchen, solltest du darüber nachdenken, was die Variable eigentlich in der Klasse verloren hat.

    Das ist doch nur ein krampfhafter versuch etwas "besser" zu machen, obwohl es nicht sein muss. Wenn ich z.B. ein CAD Programm habe und die Objekte (Kurven/Flächen) haben Namen die in verschiedenen GUI-Elementen angezeigt/umbenannt werden können, warum sollen die dann kein get/setName haben? Was würdest du machen? Warum ist das dann besser?

    Was genau ist der Grund, wieso der Name deiner Meinung nach Teil einer Kurve oder Fläche sein sollte? Imo ist der Name etwas, über das eine bestimmte Instanz einer Kurve oder Fläche von der Anwendung identifiziert werden kann. Ein Name ist aber imo nicht Teil des Konzepts einer Kurve oder Fläche. Folgedessen sollte der Name auch nicht Attribut der Klasse Kurve bzw. Fläche sein, sondern die Anwendung eine Map haben, die Namen auf Instanzen abbildet...

    Der Name ist nicht Teil des Konzepts einer Kurve oder Fläche, sondern eines Objekts. Objekte können auch nur "Gruppen" sein die andere Objekte enthalten. Die Namen der Objekte werden auch in Files gespeichert. Was soll das an deiner Map besser sein? Kennt dann GUI, FileIO usw die Applikation um den Namen zu holen?



  • volkard schrieb:

    Du könntest leicher jagen, welches taube Nüßchen Dir eine 0 in den Nenner geschrieben hat.

    Ich gehe bei solchen Klassen grundsätzlich davon aus das der Nutzer die Regeln kennt. Man kann bei dieser Sache natürlich auch public Variablen und einen Setter nehmen so das der Nutzer der Klasse den Setter nehmen kann wenn er sich unsicher ist ob an dieser Stelle evtl eine 0 kommen kann, und sich damit die Prüfung für die Fälle sparen in denen es nicht passiert.

    dot schrieb:

    Folgedessen sollte der Name auch nicht Attribut der Klasse Kurve bzw. Fläche sein, sondern die Anwendung eine Map haben, die Namen auf Instanzen abbildet...

    Das finde ich etwas übertrieben. Das bedeutet ja im Grunde das man jedesmal die Map durchsuchen muß um an den Namen zu kommen statt einfach getName() auf die Instanz aufzurufen.



  • hustbaer schrieb:

    dot schrieb:

    Getter und Setter brechen die Kapselung. Wann immer du meinst, einen Getter oder Setter zu brauchen, solltest du darüber nachdenken, was die Variable eigentlich in der Klasse verloren hat.

    Das ist ein Statement, das nur mit eine sehr engen Definition von "Getter" bzw. "Setter" Sinn macht.
    Bevor man sowas behauptet, sollte mal also besser erklären was man mit "Getter" und "Setter" meint.

    Die Aussage macht nur für triviale Getter/Setter Sinn, das ist IMHO klar und nicht erklärungsbedürftig.



  • Bashar schrieb:

    hustbaer schrieb:

    dot schrieb:

    Getter und Setter brechen die Kapselung. Wann immer du meinst, einen Getter oder Setter zu brauchen, solltest du darüber nachdenken, was die Variable eigentlich in der Klasse verloren hat.

    Das ist ein Statement, das nur mit eine sehr engen Definition von "Getter" bzw. "Setter" Sinn macht.
    Bevor man sowas behauptet, sollte mal also besser erklären was man mit "Getter" und "Setter" meint.

    Die Aussage macht nur für triviale Getter/Setter Sinn, das ist IMHO klar und nicht erklärungsbedürftig.

    Was sind triviale Getter/Setter? Ist checkbox.getState() oder textfield.getText() oder object.getName() trivial?

    Die Aussage macht eigentlich garkeinen Sinn. Getter und Setter brechen die Kapselung, wenn sie Zugriff/Modifikation von internen Daten zulassen und nicht einfach weil irgendwas so heißt. Genauso sollte man auch keine anderen public Methoden haben die Wissen über internes vom Anwender verlangen.



  • a35sw4ed5rf6t7gz8h schrieb:

    Was sind triviale Getter/Setter?

    Versuchs mal mit Google.



  • Bashar schrieb:

    a35sw4ed5rf6t7gz8h schrieb:

    Was sind triviale Getter/Setter?

    Versuchs mal mit Google.

    Finde nur Foren, sowas ist keine klare Definition und sagt schon garnichts darüber aus, was du dafür hältst.


Anmelden zum Antworten