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



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



  • Der Sinn von Gettern/Settern ist stark kontextabhängig. Man sollte sie so viel wie nötig und so wenig wie möglich einsetzen. Ich finde, das Wichtigste ist mit folgendem Beitrag gesagt:

    Nexus schrieb:

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



  • Xebov schrieb:

    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.

    Och, ich finde da macht ein Setter immer Sinn und ich würde den Nenner nicht public machen:

    class fraction
    {
    private:
        int numerator;
    
    public:
        int getNumerator() const
        {
            return numerator;
        }
    
        void setNumerator(int newValue)
        {
            assert(newValue != 0);
            numerator = newValue;
        }
    };
    

    SeppJ schrieb:

    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.

    Hey, das war ja ich. 😃



  • warum wird hier schon wieder zensiert? warum darf man nicht ironisch zeigen wie dumm die anti getter setter regel ist?



  • a35sw4ed5rf6t7gz8h schrieb:

    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?

    Wofür genau verwendest du Klassen, wenn nicht um Konzepte auszudrücken? Wenn wir uns einig sind, dass ein Name nicht Teil des Konzeptes eine Kurve oder Fläche ist, nenn mir einen Grund, wieso genau der Name dann Teil der Klasse sein sollte. Die Tatsache, dass Objekte im User Interface deiner Anwendung über Namen identifiziert werden, ist für das User Interface deiner Anwendung wesentlich, aber nicht für das mathematische Konzept einer Kurve oder Fläche. Und genau so sollte man das dann auch modellieren. Angenommen du willst nun plötzlich an anderer Stelle in deiner Anwendung mit Kurven und Flächen arbeiten, die aber nicht direkt im User Interface auftauchen. Hinter diesen Kurven und Flächen steckt immer noch um das gleiche Konzept, ein Name macht dort aber keinen Sinn...

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

    Nope, das ist meine eigene kleine UI Library für Direct3D. Mir fällt grad mir kein sinnvoller Anwendungsfall von "bewegten Fenstern" ein, aber umzusetzen wäre sowas relativ einfach, man braucht lediglich einen entsprechenden Container. Ich finde einer der Kernpunkte von gutem UI ist die Skalierbarkeit des Layouts. Das Design der Library ist ein ganz klein wenig von WPF inspiriert und vor allem auf skalierbares Layout ausgerichtet...

    Xebov schrieb:

    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.

    Wann genau müsste man denn z.B. von der Instanz an den Namen kommen?

    Nexus schrieb:

    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?

    Zunächst einmal sind wir uns denk ich einig, dass es keinen Sinn macht, einem sf::Sprite ein getName() bzw. setName() zu verpassen. 😉
    Unter einem Sprite versteht man rein prinzipiell mal ein kleines Bild, das sich irgendwo auf dem Bildschirm befindet und dessen Position verändert werden kann. Dementsprechend wird das Sprite also Methoden brauchen, die seine Position modifizieren, denn das ist für das Konzept eines Sprite wesentlich. Die ganzen Getter sind allerdings imo überflüssig. Ein Spiel verwendet Sprites um Bildchen auf den Bildschirm zu malen. Die Position dieser Bildchen kommt dabei von der Spiellogik und in einem Spiel, das sauber designed ist, geht der Datenfluss da nur in eine Richtung, denn alles andere würde bedeuten, dass die Spiellogik die Sprites als Datenablage missbraucht.

    Ethon schrieb:

    Xebov schrieb:

    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.

    Och, ich finde da macht ein Setter immer Sinn und ich würde den Nenner nicht public machen:

    class fraction
    {
    private:
        int numerator;
    
    public:
        int getNumerator() const
        {
            return numerator;
        }
    
        void setNumerator(int newValue)
        {
            assert(newValue != 0);
            numerator = newValue;
        }
    };
    

    Ich finde, dass es in der Regel keinen Sinn macht, Typen mit Wertsemantik aus einem typischen OO Blickpunkt zu betrachten. In dem konkreten Fall würde ich einfach ein struct mit zwei Membern machen und die entsprechenden Constraints über das Typsystem ausdrücken:

    struct rational
    {
      int numerator;
      nonzero_int denominator;
    };
    


  • strictly_positive_int vernünftig umzusetzen ist so dermaßen aufwendig (die ganzen operatoren, aber schon alleine weil man dann mit traits bei Grenzüberschreitungen arbeiten muss, exceptions, asserts, sonderwerte), dass ich die Idee nicht so gut finde. Der Gewinn steht einfach nicht in Relation zu den Kosten.



  • dot schrieb:

    a35sw4ed5rf6t7gz8h schrieb:

    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?

    Wofür genau verwendest du Klassen, wenn nicht um Konzepte auszudrücken? Wenn wir uns einig sind, dass ein Name nicht Teil des Konzeptes eine Kurve oder Fläche ist, nenn mir einen Grund, wieso genau der Name dann Teil der Klasse sein sollte. Die Tatsache, dass Objekte im User Interface deiner Anwendung über Namen identifiziert werden, ist für das User Interface deiner Anwendung wesentlich, aber nicht für das mathematische Konzept einer Kurve oder Fläche. Und genau so sollte man das dann auch modellieren. Angenommen du willst nun plötzlich an anderer Stelle in deiner Anwendung mit Kurven und Flächen arbeiten, die aber nicht direkt im User Interface auftauchen. Hinter diesen Kurven und Flächen steckt immer noch um das gleiche Konzept, ein Name macht dort aber keinen Sinn...

    Kannst du lesen? Nochmal: Der Name gehört nicht zur Kurve. Ich hab Kurven/Flächen in Klammer geschrieben und du baust deine ganze Argumentation darauf auf.

    Objekte können auch nur "Gruppen" sein die andere Objekte enthalten

    Versuch mal es zu verstehen.
    Ich kann auch Nodes statt Objekt schreiben, vlt kapierst du dann um was es geht. Ist mir aber auch egal.


Anmelden zum Antworten