Ist es eine schlechte Praxis, wenn meine Getter-Methode den gespeicherten Wert ändert?

70

Ist es eine schlechte Praxis, meine Getter-Methode wie Version 2 in meiner Klasse zu ändern?

Version 1:

 public String getMyValue(){
     return this.myValue
 }

Version 2:

 public String getMyValue(){

    if(this.myValue == null || this.myValue.isEmpty()){
       this.myValue = "N/A";
    }

    return this.myValue;
 }
jemand
quelle
5
Imho ist es in Ordnung, wenn diese Nebenwirkung in den Dokumenten klar dokumentiert ist
jlordo
Ich bevorzuge, dass getterFunktionen niemals den Wert des Objekts ändern. Sie können diese Prüfung in einer anderen Funktion durchführen und den Wert in einer setterFunktion festlegen . Nur um einen klaren Code zu haben.
Maroun
3
Ich denke, das ist schlecht, weil es so aussieht, als würden Sie Ihre Präsentation mit Ihrem Datenmodell mischen. Was passiert, wenn Ihre App in eine andere Sprache übersetzt werden muss?
MTilsted
8
Ich habe nichts von Ihrer Änderung gefunden, aber im Allgemeinen denke ich, dass es in Ordnung ist, einen Getter zu ändern. Schließlich ist der Getter eine Abstraktion, die es uns ermöglicht , das interne Verhalten zu ändern, ohne anderen Code zu beschädigen.
Matsemann
2
Sollte der Fragentitel nicht lauten, Is it bad practice for a getter to change an object's member's value?da es sich so anhört, als würden Sie sich fragen, ob es schlecht ist, wenn sich die interne Implementierung eines Getters ändert, auf die ich glaube, dass die Antwort Nein lautet. Es ist in Ordnung, sie zu ändern.
Vikki

Antworten:

117

Ich denke, es ist eigentlich eine ziemlich schlechte Praxis, wenn Ihre Getter- Methoden den internen Zustand des Objekts ändern.

Um das gleiche zu erreichen würde ich vorschlagen , nur Rückkehr der "N/A".

  • Im Allgemeinen kann dieses interne Feld an anderen Stellen (intern) verwendet werden, für die Sie die Getter-Methode nicht verwenden müssen. Am Ende könnte der Aufruf von also foo.getMyValue()tatsächlich das Verhalten von ändern foo.

Alternativ könnte die Übersetzung von nullnach "N/A"im Setter erfolgen , dh der interne Wert könnte auf gesetzt werden, "N/A"wenn übergeben nullwird.


Eine allgemeine Bemerkung:
Ich würde nur Zustände hinzufügen, beispielsweise "N/A"wenn sie von einer API oder einer anderen Instanz erwartet werden, die auf Ihrem Code basiert. Ist dies nicht der Fall, sollten Sie sich auf die Standardnulltypen verlassen, die Ihnen in Ihrer Programmiersprache zur Verfügung stehen.

Fgysin setzt Monica wieder ein
quelle
43
Nur eine Anmerkung: Ich bin der Meinung, dass Getter den internen Status eines Objekts beim Lazy-Loading ändern können, wenn Sie Daten nur dann laden möchten, wenn der Getter aufgerufen wird.
Vincent Mimoun-Prat
5
Fair genug, das ist ein gültiger Anwendungsfall. Die von OP beschriebene Situation könnte jedoch zu schrecklichen Nebenwirkungen führen.
Fgysin wieder Monica
4
Es gibt nichts ärgerlicheres, als sich mit einer Eigenschaft zu befassen, die den Status des Getters ändert und den Status beim Debuggen jedes Mal ändert, wenn eine Komponente des Debuggers darauf zugreift.
Chuu
6
Ich glaube nicht, dass es ein Problem gibt, den internen Zustand eines Objekts in einem Getter zu ändern. Der interne Status eines Objekts ist Sache des Klassenautors. Als Benutzer der Klasse sollten Sie nicht wissen (oder sich darum kümmern), was intern geschieht, solange die externe Schnittstelle konsistent ist . Unabhängig davon, ob er den Wert im Setter oder träge im Getter festlegt, ist dies vollständig gültig. Wichtig ist, dass der Getter konsistent N / A für Null- oder Leerwerte zurückgibt.
Laurent
1
Stimmen Sie mit @Laurent überein, dies ist einfach eine verzögerte Initialisierung der Instanzvariablen und ist eine weit verbreitete Praxis. Ich bin mir nicht sicher, .isEmpty()ob "N/A"ich dagegen prüfen oder sogar als Standardwert verwenden soll (ich würde wahrscheinlich ein Nullobjekt oder eine Ausnahme bevorzugen, da der Wert / die Behandlung für den Standardfall oft von der aufrufenden Seite abhängt, nicht nur vom aufgerufenen Objekt)
Damien Pollet
38

Meiner Meinung nach lazy-loadingsollten Getter den Wert nicht ändern , es sei denn, Sie tun dies (was Sie in diesem Fall nicht tun ). Also würde ich entweder:

Legen Sie das Wechselgeld in den Setter

public void setMyValue(String value) {
    if(value == null || value.isEmpty()){
        this.myValue = "N/A";
    } else {
        this.myValue = value;
    }
}

Oder lassen Sie den Getter einen Standardwert zurückgeben, wenn der Wert nicht richtig eingestellt ist:

public String getMyValue() {
    if(this.myvalue == null || this.myvalue.isEmpty()){
        return "N/A";
    }    
    return this.myValue;
}

Im Fall von Lazy-Loading, wo ich sagen würde, dass es in Ordnung ist, Ihre Mitglieder in einem Getter zu ändern, würden Sie Folgendes tun:

public String getMyValue() {
    if (this.myvalue == null) {
        this.myvalue = loadMyValue();
    }    
    return this.myValue;
}
Vincent Mimoun-Prat
quelle
Warum würden Sie Ihre faule Lademethode get ... () nennen? Es so etwas wie Laden zu nennen ... () scheint angemessener zu sein, nicht wahr?
Lucas Hoepner
Weil der Getter den Wert direkt zurückgibt, es sei denn, er wurde noch nie zuvor geladen (daher der Aufruf loadMyValueinnerhalb des Getters). Das Aufrufen des Getter loadMyValue würde (meiner Meinung nach) bedeuten, dass der Wert geladen wird, egal was passiert.
Vincent Mimoun-Prat
11

Du machst hier zwei Dinge. Erhalten und einstellen.

Mark W.
quelle
Ich bevorzuge eigentlich die akzeptierte Antwort. Es besagt, dass Sie den Wert "N / A" zurückgeben könnten, anstatt zuerst die Klassenvariable zu ändern.
Mark W
10

Ja. Es ist eine schlechte Praxis.

Warum?

Wenn der Wert festgelegt ist (in einer Konstruktor- oder Setter-Methode), sollte er validiert werden, nicht wenn eine Getter-Methode aufgerufen wird. Es private validate*ist auch eine gute Idee, eine Methode dafür zu erstellen.

private boolean validateThisValue(String a) {
     return this.myValue != null && !this.myValue.isEmpty();
}

public void setThisValue(String a) {
    if (validateThisValue(a)) {
        this.myValue = a;
    } 
    else {
        // do something else
        // in this example will be
        this.myValue = "N/A";
    }
}

Und ändern Sie bei der Getter-Methode niemals den Status des Objekts. Ich habe an einigen Projekten gearbeitet, und der Getter muss oft gemacht werden const: "Diese Methode kann den internen Zustand nicht ändern".

Zumindest, wenn man die Dinge nicht verkomplizieren will, in der Getter - Methode, sollten Sie zurückkehren "N/A" , anstatt ändern interner Zustand und Satz myValuezu "N/A".

hqt
quelle
4
Ich bin nicht damit einverstanden, niemals einen Wert in einem Setter zu ändern. Der gesamte Zweck der Verwendung von Getter / Setter besteht darin, interne und externe Implementierungen zu abstrahieren. Person.setHeightInCentimeters(int value),, Person.setHeightInMeters(double value)und Person.setHeightInFeetAndInches(int feet, int inches)sollten alle eine einzige interne Darstellung gemeinsam haben, was bedeutet, dass mindestens zwei von ihnen etwas anderes als die Eingabewerte speichern.
Dan spielt am Feuer
Ah. Es tut mir so leid :( Ich tippe Mismatch, ändere nie etwas in Getter. Nicht Setter. Wie du in meinem Code siehst, habe ich den internen Status von Setter geändert. Ich habe bearbeitet. Es tut mir so leid.
hqt
6

Normalerweise definiere ich eine bestimmte getter.

Ändern Sie niemals das Original getter:

 public String getMyValue(){
     return this.myValue
 }

Und erstellen Sie eine bestimmte getter:

public String getMyValueFormatted(){

    if(this.myvalue == null || this.myvalue.isEmpty()){
       return "N/A";
    }else{
       return this.myValue;
    }
 }
Rodrigo
quelle
Woher weißt du, wen du wann anrufen sollst?
Abhishek Mehta
Die zweite Methode dient der Anzeige für den Benutzer.
Rodrigo
Also sollte der 1. kein Publikum sein?
Abhishek Mehta
Beide sind öffentlich. Wird zuerst verwendet, um den Rohwert zu erhalten. Wenn ein formatierter Wert benötigt wird, verwenden Sie den zweiten. Einfach, Sie brauchen keine komplizierten getter/setterMethoden.
Rodrigo
1
Es wäre verwirrend für einen neuen Entwickler, der die API aufruft. 1. Ansatz: Benennen Sie die erste öffentliche Methode in getMyValueOriginal und die zweite Methode in getMyValueFormatted um.
Abhishek Mehta
5

Ich denke, es ist besser zu initialisieren this.myValue = "N/A". Und nachfolgende Anrufe an setMyValuesollten die this.myValueentsprechend Ihren Geschäftsbedingungen ändern .
Das getMyValuesollte sich in keiner Weise ändern this.myValue. Wenn Sie einen bestimmten Wert zurückgeben möchten, sollten Sie diesen Wert (wie "N / A") zurückgeben und nicht ändern this.myValue. Getter dürfen den Wert des Mitglieds nicht ändern.

George D.
quelle
4

Ich würde die Setter-Methode besser ändern. Wenn der Wert nullleer oder leer ist, N/Awird er dem Attribut zugewiesen. Wenn Sie das Attribut also in anderen Methoden innerhalb der Klasse (vg toString()) verwenden, haben Sie dort den beabsichtigten Wert.

Alternativ können Sie die Setter-Methode ändern, um eine Ausnahme zu starten, wenn der eingestellte Wert nicht richtig ist, sodass der Programmierer gezwungen ist, seine Handhabung zu verbessern, bevor er den Wert einstellt.

Davon abgesehen ist es in Ordnung.

SJuan76
quelle
4

Ich halte dies für eine schlechte Praxis, es sei denn und bis Sie den Grund erklären, warum es so notwendig ist, dass Sie das Objekt innerhalb der Getter-Methode ändern, anstatt es innerhalb der Setter-Methode zu tun.
Haben Sie das Gefühl, dass dies aus irgendeinem Grund nicht möglich ist? Könnten Sie bitte näher darauf eingehen?

ramesh
quelle
4

Mach, was immer du willst. Immerhin sind Getter und Setter nur eine weitere öffentliche Methode. Sie können auch andere Namen verwenden.

Wenn Sie jedoch Frameworks wie verwenden Spring, müssen Sie diese Standardnamen verwenden, und Sie sollten niemals Ihre benutzerdefinierten Codes in diese einfügen.

Mawia
quelle
4

absolut ja, es ist eine schlechte Praxis.

Stellen Sie sich vor, Sie kommunizieren netzwerkübergreifend mit einem Drittanbieter (Remoting, COM, ...). Dies erhöht den Roundtrip und beeinträchtigt dann die Anwendungsleistung.

xPridex
quelle
4

Ein Setter kann im Rahmen der Validierung Änderungen vornehmen, ein Getter sollte jedoch den Wert zurückgeben und die Validierung vom Aufrufer durchführen lassen. Wenn Sie tun , Validieren, dann sollte wie zu dokumentieren.

Bizmarck
quelle
3

Dies hängt in hohem Maße von dem Vertrag ab, den Sie mit Ihrer get () - Methode durchsetzen möchten. Gemäß den Design-by-Contract-Konventionen muss der Anrufer sicherstellen, dass die Voraussetzungen erfüllt sind (was bedeutet, dass eine Validierung in einer Setter-Methode häufig ein schlechtes Design ist) und der Angerufene (ich weiß nicht, ob dies der richtige englische Begriff für ist) das, dh der Angerufene) stellt sicher, dass die Post-Bedingungen erfüllt sind.

Wenn Sie Ihren Vertrag so definieren, dass die Methode get () - das Objekt nicht ändern darf, brechen Sie Ihren eigenen Vertrag. Denken Sie darüber nach, eine Methode wie zu implementieren

public isValid() {
    return (this.myvalue == null || this.myvalue.isEmpty());
}

Der Vorteil dieses Ansatzes besteht darin, dass Sie nicht überprüfen müssen, ob die Rückgabe von get () "N / A" oder etwas anderes ist. Dies kann auch vor dem Aufruf von set () aufgerufen werden, um zu überprüfen, ob Sie keine unzulässigen Werte in Ihr Objekt einfügen.

Wenn Sie einen Standardwert festlegen möchten, sollten Sie dies während der Initialisierung tun.

Lucas Hoepner
quelle
3

Zustandsänderungen bei Gettern sollten eine hängende Straftat sein. Dies bedeutet, dass der Client-Code in der Reihenfolge, in der er auf Getter und Setter zugreift, vorsichtig sein muss. Dazu muss er über Kenntnisse der Implementierung verfügen. Sie sollten in der Lage sein, die Getter in beliebiger Reihenfolge aufzurufen und trotzdem die gleichen Ergebnisse zu erzielen. Ein verwandtes Problem tritt auf, wenn der Setter den eingehenden Wert abhängig vom aktuellen Status des Objekts ändert.

Kevin Whitefoot
quelle
1
Genau! Wenn Sie ein Seil brauchen, lassen Sie es mich bitte wissen.
Alexandre M
2

Zu diesem Zweck können Sie einen Werthalter verwenden. Wie Optionale Klasse in der Guavenbibliothek.

Aleksander Gralak
quelle