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



  • 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.



  • Cool ist auch, wenn man versucht "Get" und "Set" zu vermeiden, stattdessen zwei Überladungen (non-const und const mit retval) macht und dann bei std::bind die Quittung bekommt -.-

    Dot: Ist Dein GUI-Code irgendwo einsehbar? Ich stelle mir das arg blöde vor, damit bewegbare Fenster und so Zeugs zu implementieren. Wenn das alles natürlich immer nur vom Parent oder wem anders gelayoutet wird, ists natürlich okay...



  • Decimad schrieb:

    Dot: Ist Dein GUI-Code irgendwo einsehbar? Ich stelle mir das arg blöde vor, damit bewegbare Fenster und so Zeugs zu implementieren. Wenn das alles natürlich immer nur vom Parent oder wem anders gelayoutet wird, ists natürlich okay...

    Klingt nach GTK.



  • hustbaer schrieb:

    Das ist ein Statement, das nur mit eine sehr engen Definition von "Getter" bzw. "Setter" Sinn macht.

    Oder nicht einmal da.

    Nehmt als Beispiel die SFML-Klasse sf::Sprite. Da gibts viele set/get-Methoden, um auf einzelne Attribute wie Position, Rotation, Skalierung, Textur, Textur-Rechteck, Farbe, etc. zuzugreifen. Was genau ist daran schlecht, und wie würdet ihr sowas besser designen?



  • @Nexus: Also ich ziehe aus diesen Diskussionen immer die Aussage, dass eben alles gekapselt sein sollte. Seither habe ich den Monitor immer mit Pappe zugedeckt, damit ich nicht Software-Interna sehen muss. Die Tastatur ist natürlich abgestöpselt. Nur dieses Forum liegt mir am Herzen, da mache ich ab und zu eine Ausnahme.


  • Mod

    Irgendwie habe ich das Gefühl, dass hier in diesem Thread absichtlich vieles falsch verstanden oder ausgelegt wird - von beiden allen Seiten.

    Absolute statements are always wrong. Nicht alles wo get oder set dransteht ist ein trivialer Getter/Setter (d.h. eine Memberfunktion in der einfach return membervariable; steht und ihr Setter-Äquivalent). Nicht alle guten Modelle schließen kategorisch aus, dass es auch mal diese trivialen Getter/Setter für die Member einer Klasse gibt.

    Hier kommt nun mein eigener Beitrag zum Thema: Wie volkard bereits so schön verlinkt hat, tendieren viele Anfänger, oftmals aufgrund schlechter Vorbilder, dazu, zu einem Datenmember einer Klasse automatisch einen trivialen Getter und Setter zu schreiben. Manche benutzen dafür sogar Funktionen ihrer IDE, ich erinnere mich sogar an einen Thread, in dem stolz ein Makro a la

    #define MEMBER_VAR(type, name)    \
    private:                          \
     type name;                       \
    public:                           \
     type get_##name () const         \
      { return name ; }               \
     void set_##name (type arg)       \
      { name = arg; }
    

    vorgestellt wurde. Es ist wohl jedem einsichtig, dass dieses zwanghafte Anlegen von Gettern und Settern keine gute Praxis ist, oder? Da brauche ich auch keine weitergehende Begründung und Alternativen zu nennen, denke ich.


Anmelden zum Antworten