1878 Stimmen

Warum Getter und Setter/Accessors verwenden?

Was ist der Vorteil der Verwendung von Gettern und Settern - die nur abfragen und setzen - anstatt einfach öffentliche Felder für diese Variablen zu verwenden?

Wenn Getter und Setter jemals mehr tun als nur das einfache Get/Set, kann ich dies sehr schnell herausfinden, aber ich bin nicht 100% klar, wie:

public String foo;

schlechter ist als:

private String foo;
public void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return foo; }

Ersteres hingegen erfordert viel weniger Standardcode.

8 Stimmen

10 Stimmen

Natürlich ist beides gleich schlecht, wenn das Objekt keine zu ändernde Eigenschaft benötigt. Ich würde lieber alles privat machen, und dann Getter hinzufügen, wenn es nützlich ist, und Setter, wenn es nötig ist.

31 Stimmen

Google "accessors are evil"

5voto

Pritam Banerjee Punkte 16396

Getter y Einsteller werden verwendet, um zwei der grundlegenden Aspekte der objektorientierten Programmierung zu implementieren, nämlich:

  1. Abstraktion
  2. Verkapselung

Angenommen, wir haben eine Klasse Employee:

package com.highmark.productConfig.types;

public class Employee {

    private String firstName;
    private String middleName;
    private String lastName;

    public String getFirstName() {
      return firstName;
    }
    public void setFirstName(String firstName) {
       this.firstName = firstName;
    }
    public String getMiddleName() {
        return middleName;
    }
    public void setMiddleName(String middleName) {
         this.middleName = middleName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getFullName(){
        return this.getFirstName() + this.getMiddleName() +  this.getLastName();
    }
 }

Hier werden die Implementierungsdetails von Full Name vor dem Benutzer verborgen und sind im Gegensatz zu einem öffentlichen Attribut für den Benutzer nicht direkt zugänglich.

3 Stimmen

Für mich mit Tonnen von Getter und Setter, die nichts einzigartig tun ist nutzlos. getFullName ist eine Ausnahme, weil es etwas anderes tut. Wenn man nur die drei Variablen öffentlich macht und getFullName beibehält, wird das Programm einfacher zu lesen sein, aber die Sache mit dem Vollnamen bleibt trotzdem verborgen. Im Allgemeinen bin ich völlig in Ordnung mit Gettern und Settern, wenn a. sie etwas Einzigartiges tun und/oder b. man nur einen hat, ja, man könnte ein public final und all das haben, aber nein

2 Stimmen

Der Vorteil dabei ist, dass Sie die Interna der Klasse ändern können, ohne die Schnittstelle zu ändern. Angenommen, Sie haben statt drei Eigenschaften nur eine - ein Array von Strings. Wenn Sie Getter und Setter verwendet haben, können Sie diese Änderung vornehmen und dann die Getter/Setter so aktualisieren, dass sie wissen, dass names[0] der Vorname ist, names[1] der mittlere Name, usw. Wenn Sie jedoch nur öffentliche Eigenschaften verwenden, müssten Sie auch jede Klasse ändern, die auf Employee zugreift, da die Eigenschaft firstName, die sie bisher verwendet haben, nicht mehr existiert.

3 Stimmen

@AndrewHows nach dem, was ich im wirklichen Leben gesehen habe, ändern die Leute, wenn sie die Interna der Klasse ändern, auch die Schnittstelle und führen ein großes Refactoring des gesamten Codes durch

5voto

aditya lath Punkte 340

Es gibt einen Unterschied zwischen DataStructure und Object.

Die Datenstruktur sollte ihr Innenleben und nicht ihr Verhalten offenlegen.

Ein Objekt sollte nicht sein Inneres, sondern sein Verhalten offenlegen, was auch als das Gesetz von Demeter bekannt ist

Meistens werden DTOs eher als eine Datenstruktur und nicht als Objekt betrachtet. Sie sollten nur ihre Daten und nicht ihr Verhalten offenlegen. Mit Setter/Getter in DataStructure wird das Verhalten anstelle der Daten darin offengelegt. Dies erhöht die Wahrscheinlichkeit einer Verletzung von Das Gesetz der Demeter .

Onkel Bob erklärt in seinem Buch Clean Code das Gesetz der Demeter.

Es gibt eine bekannte Heuristik, das Gesetz der Demeter, das besagt, dass ein Modul nichts über das Innere der Objekte wissen sollte, die es manipuliert. Wie wir im letzten Abschnitt gesehen haben, verbergen Objekte ihre Daten und legen Operationen offen. Das bedeutet, dass ein Objekt seine interne Struktur nicht interne Struktur eines Objekts nicht durch Accessoren offenlegen, da dies eher eine Offenlegung als seine interne Struktur zu verbergen.

Genauer gesagt, besagt das Gesetz von Demeter, dass eine Methode f einer Klasse C nur die Methoden dieser Klasse aufrufen darf:

  • C
  • Ein mit f erstelltes Objekt
  • Ein Objekt, das als Argument an f übergeben wird
  • Ein Objekt, das in einer Instanzvariablen von C

Die Methode sollte keine Methoden für Objekte aufrufen, die von einer der zulässigen Funktionen zurückgegeben werden. Mit anderen Worten: Reden Sie mit Freunden, nicht mit Fremden.

Ein Beispiel für einen Verstoß gegen die LoD ist demnach:

final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();

Hier sollte die Funktion die Methode seines unmittelbaren Freundes aufrufen, der hier ctxt ist, es sollte nicht die Methode des Freundes seines unmittelbaren Freundes aufrufen. aber diese Regel gilt nicht für Datenstruktur. so hier, wenn ctxt, Option, ScratchDir Datastructure dann sind, warum ihre internen Daten mit einigen Verhalten zu wickeln und eine Verletzung von LoD zu tun.

Stattdessen können wir etwa so vorgehen.

final String outputDir = ctxt.options.scratchDir.absolutePath;

Dies erfüllt unsere Bedürfnisse und verstößt nicht einmal gegen die LoD.

Inspiriert von Clean Code von Robert C. Martin (Onkel Bob)

5voto

GeZo Punkte 61

Es gibt einen guten Grund, die Verwendung von Accessors zu erwägen, da es keine Eigenschaftsvererbung gibt. Siehe nächstes Beispiel:

public class TestPropertyOverride {
    public static class A {
        public int i = 0;

        public void add() {
            i++;
        }

        public int getI() {
            return i;
        }
    }

    public static class B extends A {
        public int i = 2;

        @Override
        public void add() {
            i = i + 2;
        }

        @Override
        public int getI() {
            return i;
        }
    }

    public static void main(String[] args) {
        A a = new B();
        System.out.println(a.i);
        a.add();
        System.out.println(a.i);
        System.out.println(a.getI());
    }
}

Sortie :

0
0
4

5voto

user982042 Punkte 179

Wenn Sie keine Validierungen benötigen und nicht einmal den Zustand aufrechterhalten müssen, d.h. eine Eigenschaft hängt von einer anderen ab, so dass wir den Zustand aufrechterhalten müssen, wenn eine geändert wird. Sie können es einfach halten, indem Sie das Feld öffentlich machen und keine Getter und Setter verwenden.

Ich denke, dass OOPs die Dinge verkomplizieren, wenn das Programm wächst, wird es für den Entwickler zum Albtraum, es zu skalieren.

Ein einfaches Beispiel: Wir generieren C++-Header aus Xml. Der Header enthält ein einfaches Feld, für das keine Validierung erforderlich ist. Aber immer noch wie in OOPS accessor sind Mode wir sie wie folgt generiert.

const Filed& getfield() const
Field& getField() 
void setfield(const Field& field){...} 

was sehr ausführlich ist und nicht benötigt wird. eine einfache

struct 
{
   Field field;
};

ist ausreichend und lesbar. Bei der funktionalen Programmierung gibt es kein Konzept für das Verstecken von Daten, es ist sogar nicht erforderlich, da die Daten nicht verändert werden.

5voto

bobobobo Punkte 61051

Code entwickelt sich . private ist ideal, wenn Sie brauchen den Schutz der Daten von Mitgliedern . Letztendlich sollten alle Klassen eine Art "Miniprogramme" sein, die eine klar definierte Schnittstelle haben. dass man nicht einfach an den Interna des Systems herumschrauben kann .

Davon abgesehen, Software-Entwicklung geht es nicht darum, die endgültige Version des Kurses so hinzustellen, als ob man eine gusseiserne Statue beim ersten Versuch drücken würde. Während man damit arbeitet, ist der Code eher wie Ton. Sie entwickelt sich weiter während Sie es entwickeln und mehr über den Problembereich erfahren, den Sie lösen wollen. Während der Entwicklung können Klassen miteinander interagieren, als sie sollten (Abhängigkeit, die Sie planen, auszugleichen), miteinander verschmelzen oder sich aufspalten. Ich denke, die Debatte läuft darauf hinaus, dass die Leute nicht religiös schreiben wollen

int getVar() const { return var ; }

Sie haben also:

doSomething( obj->getVar() ) ;

Anstelle von

doSomething( obj->var ) ;

Es ist nicht nur getVar() visuell verrauscht, es erweckt den Eindruck, dass gettingVar() ein komplexerer Prozess ist, als er in Wirklichkeit ist. Wie Sie (als Klassenschriftsteller) die Unantastbarkeit der var ist besonders verwirrend für einen Benutzer Ihrer Klasse, wenn sie einen Passthru-Setter hat - dann sieht es so aus, als ob Sie diese Gates aufstellen, um etwas zu "schützen", das Sie für wertvoll halten (die Unantastbarkeit von var ), aber selbst Sie räumen ein var Die Möglichkeit, dass jeder einfach reinkommt und die Daten abruft, macht den Schutz des Unternehmens wertlos. set var zu jedem beliebigen Wert, ohne dass Sie auch nur einen Blick darauf werfen, was sie tun.

Ich programmiere also wie folgt (unter der Annahme eines "agilen" Ansatzes - d.h., wenn ich Code schreibe, ohne zu wissen genau was es tun wird/keine Zeit oder Erfahrung für die Planung einer aufwendigen Wasserfallschnittstelle hat):

1) Beginnen Sie mit allen öffentlichen Mitgliedern für grundlegende Objekte mit Daten und Verhalten. Aus diesem Grund werden Sie in meinem gesamten C++ "Beispiel"-Code feststellen, dass ich struct anstelle von class überall.

2) Wenn das interne Verhalten eines Objekts für ein Datenelement komplex genug wird (z.B. wenn es eine interne std::list in irgendeiner Reihenfolge), werden Funktionen vom Typ Accessor geschrieben. Da ich selbst programmiere, setze ich nicht immer das Mitglied private sofort, aber irgendwann im Laufe der Entwicklung der Klasse wird das Mitglied "befördert" zu entweder protected o private .

3) Klassen, die vollständig ausgearbeitet sind und strenge Regeln für ihre Interna haben (z.B. sie genau wissen, was sie tun, und Sie nicht mit seinen Interna "fummeln" (Fachbegriff) dürfen, erhalten die class Bezeichnung, standardmäßig private Mitglieder, und nur einige wenige Mitglieder dürfen public .

Ich finde, dieser Ansatz ermöglicht es mir zu vermeiden, dort zu sitzen und religiös zu schreiben Getter/Setter, wenn eine Menge von Daten Mitglieder migriert werden, verschoben, etc. während der frühen Phasen der Entwicklung einer Klasse.

1 Stimmen

"... eine wohldefinierte Schnittstelle, an deren Interna man nicht einfach herumschrauben kann" und Validierung in Settern.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X