Wie würden Sie innerhalb einer Objektmethode auf Objekteigenschaften zugreifen? [geschlossen]

96

Was ist die "puristische" oder "richtige" Methode, um über eine Objektmethode, die keine Getter / Setter-Methode ist, auf die Eigenschaften eines Objekts zuzugreifen?

Ich weiß, dass Sie von außerhalb des Objekts einen Getter / Setter verwenden sollten, aber von innen würden Sie einfach Folgendes tun:

Java:

String property = this.property;

PHP:

$property = $this->property;

oder würdest du tun:

Java:

String property = this.getProperty();

PHP:

$property = $this->getProperty();

Verzeihen Sie mir, wenn mein Java ein wenig abweicht, es ist ein Jahr her, seit ich in Java programmiert habe ...

BEARBEITEN:

Es scheint, dass die Leute davon ausgehen, dass ich nur über private oder geschützte Variablen / Eigenschaften spreche. Als ich OO lernte, wurde mir beigebracht, Getter / Setter für jede einzelne Eigenschaft zu verwenden, auch wenn diese öffentlich war (und tatsächlich wurde mir gesagt, dass ich niemals eine Variable / Eigenschaft öffentlich machen soll). Ich gehe also möglicherweise von Anfang an von einer falschen Annahme aus. Es scheint, dass die Leute, die diese Frage beantworten, vielleicht sagen, dass Sie öffentliches Eigentum haben sollten und dass diese keine Getter und Setter brauchen, was gegen das verstößt, was mir beigebracht wurde und worüber ich gesprochen habe, obwohl das vielleicht als diskutiert werden muss Gut. Das ist wahrscheinlich ein gutes Thema für eine andere Frage ...

cmcculloh
quelle

Antworten:

62

Dies hat religiöses Kriegspotential, aber es scheint mir, dass Sie, wenn Sie einen Getter / Setter verwenden, ihn auch intern verwenden sollten - wenn Sie beide verwenden, führt dies später zu Wartungsproblemen (z. B. fügt jemand einem Setter Code hinzu, der benötigt wird wird jedes Mal ausgeführt, wenn diese Eigenschaft festgelegt wird und die Eigenschaft intern festgelegt wird, ohne dass der Setter aufgerufen wird.

Greg Hurlman
quelle
In einem Setter wird nichts anderes getan, als den Wert der Eigenschaft als Beispiel für eine falsche Verwendung in Java festzulegen.
Euphorie83
1
@ euphoria83 Vielleicht, aber das schließt es nicht aus.
Greg Hurlman
Ich stimme der ursprünglichen Antwort zu. Denken Sie jedoch daran, dass Sie, wenn Sie innerhalb der Klasse oder des Objekts etwas Privates festlegen oder abrufen, sicherstellen müssen, dass der Getter / Setter nicht zyklisch oder redundant ist, was dazu führt, dass Ihr Code fehlschlägt. Wenn Sie den Getter / Setter nicht verwenden können, greifen Sie direkt darauf zu. (Beispiel: Ihr Getter / Setter greift auf eine sekundäre (private / geschützte) Methode zu, um die Daten
Rick Mac Gillis
43

Persönlich halte ich es für wichtig, konsequent zu bleiben. Wenn Sie Getter und Setter haben, verwenden Sie diese. Ich würde nur dann direkt auf ein Feld zugreifen, wenn der Accessor viel Overhead hat. Es mag sich so anfühlen, als würden Sie Ihren Code unnötig aufblähen, aber es kann in Zukunft sicherlich eine Menge Kopfschmerzen ersparen. Das klassische Beispiel:

Möglicherweise möchten Sie später die Funktionsweise dieses Felds ändern. Vielleicht sollte es im laufenden Betrieb berechnet werden, oder Sie möchten einen anderen Typ für den Hintergrundspeicher verwenden. Wenn Sie direkt auf Eigenschaften zugreifen, kann eine solche Änderung eine Menge Code in einem einzigen Schritt zerstören.

MojoFilter
quelle
26

Ich bin ziemlich überrascht, wie einstimmig das Gefühl ist gettersund die Setter sind in Ordnung und gut. Ich schlage den Brandartikel von Allen Holub " Getters And Setters Are Evil " vor. Zugegeben, der Titel ist für den Schockwert, aber der Autor macht gültige Punkte.

Wenn Sie gettersund settersfür jedes einzelne private Feld haben, machen Sie diese Felder im Wesentlichen so gut wie öffentlich. Es würde Ihnen sehr schwer fallen, den Typ eines privaten Feldes ohne Welligkeitseffekte für jede Klasse zu ändern, die dies nennt getter.

Darüber hinaus sollten Objekte aus rein OO-Sicht auf Nachrichten (Methoden) reagieren, die ihrer (hoffentlich) Einzelverantwortung entsprechen. Die überwiegende Mehrheit von gettersund settersmacht für ihre Bestandteile keinen Sinn; Pen.dispenseInkOnto(Surface)macht für mich mehr Sinn als Pen.getColor().

Getter und Setter ermutigen Benutzer der Klasse außerdem, das Objekt nach Daten zu fragen, eine Berechnung durchzuführen und dann einen anderen Wert im Objekt festzulegen, der besser als prozedurale Programmierung bekannt ist. Es wäre besser, wenn Sie dem Objekt einfach sagen würden, dass es das tun soll, was Sie ursprünglich wollten. auch als Information Expert Idiom bekannt.

Getter und Setter sind jedoch notwendige Übel an der Grenze der Ebenen - Benutzeroberfläche, Persistenz usw. Durch den eingeschränkten Zugriff auf die Interna einer Klasse, wie z. B. das Friend-Schlüsselwort von C ++, den paketgeschützten Zugriff von Java, den internen Zugriff von .NET und das Friend-Klassenmuster, können Sie die Sichtbarkeit gettersund die Setter nur auf diejenigen reduzieren, die sie benötigen.

moffdub
quelle
19

Dies hängt davon ab, wie die Eigenschaft verwendet wird. Angenommen, Sie haben ein Schülerobjekt mit einer Namenseigenschaft. Sie können Ihre Get-Methode verwenden, um den Namen aus der Datenbank abzurufen, sofern er noch nicht abgerufen wurde. Auf diese Weise reduzieren Sie unnötige Aufrufe der Datenbank.

Angenommen, Sie haben einen privaten Ganzzahlzähler in Ihrem Objekt, der zählt, wie oft der Name aufgerufen wurde. Möglicherweise möchten Sie die Get-Methode nicht innerhalb des Objekts verwenden, da dies zu einer ungültigen Anzahl führen würde.

Shawn
quelle
Wenn das Student-Objekt ein Geschäfts- / Domänenobjekt ist, mischen Sie jetzt Infrastrukturdetails. Im Idealfall sollten sich Geschäfts- / Domänenobjekte nur mit Geschäfts- / Domänenlogik befassen.
Moffdub
Was ist, wenn Sie dem Getter eine Art Booleschen Wert hinzufügen, wie: PHP: public function getName ($ externalCall = true) {if ($ externalCall) {$ this-> incrementNameCalled (); } return $ this-> name; } und dann, wenn Sie innerhalb des Objekts selbst get name aufgerufen haben, können Sie verhindern, dass es inkrementiert wird durch: PHP: $ name = $ this-> getName (false); Gehe ich hier nur über Bord?
cmcculloh
14

PHP bietet eine Vielzahl von Möglichkeiten, um damit umzugehen, einschließlich magischer Methoden __getund __set, aber ich bevorzuge explizite Getter und Setter. Hier ist der Grund:

  1. Die Validierung kann in Setter (und Getter für diese Angelegenheit) gestellt werden.
  2. Intellisense arbeitet mit expliziten Methoden
  3. Keine Frage, ob eine Eigenschaft schreibgeschützt, schreibgeschützt oder schreibgeschützt ist
  4. Das Abrufen virtueller Eigenschaften (dh berechneter Werte) entspricht den regulären Eigenschaften
  5. Sie können einfach eine Objekteigenschaft festlegen, die an keiner Stelle tatsächlich definiert ist und die dann nicht dokumentiert wird
Unbeschriftetes Fleisch
quelle
13

Gehe ich hier nur über Bord?

Vielleicht ;)

Ein anderer Ansatz wäre, eine private / geschützte Methode zu verwenden, um das Abrufen tatsächlich durchzuführen (Caching / db / etc), und einen öffentlichen Wrapper dafür, der die Anzahl erhöht:

PHP:

public function getName() {
    $this->incrementNameCalled();
    return $this->_getName();
}

protected function _getName() {
    return $this->name;
}

und dann aus dem Objekt selbst heraus:

PHP:

$name = $this->_getName();

Auf diese Weise können Sie dieses erste Argument immer noch für etwas anderes verwenden (z. B. das Senden eines Flags, ob hier zwischengespeicherte Daten verwendet werden sollen oder nicht).

pix0r
quelle
12

Ich muss hier den Punkt verfehlen, warum sollten Sie einen Getter in einem Objekt verwenden, um auf eine Eigenschaft dieses Objekts zuzugreifen?

Um dies zu Ende zu bringen, sollte der Getter einen Getter nennen, der einen Getter nennen sollte.

Ich würde also sagen, dass der Zugriff auf eine Eigenschaft innerhalb einer Objektmethode direkt ist, insbesondere wenn der Aufruf einer anderen Methode in diesem Objekt (die ohnehin nur direkt auf die Eigenschaft zugreift und sie dann zurückgibt) nur eine sinnlose, verschwenderische Übung ist (oder ich die Frage falsch verstanden habe ).

Eierwagen
quelle
Ich war von dem gleichen Bedürfnis getrieben, das du kommentieren musstest ... Außerdem wurde es nicht geschlossen beantwortet;)
Egg Vans
8

Der puristische OO-Weg besteht darin, beides zu vermeiden und dem Gesetz von Demeter zu folgen, indem der Tell Don't Ask- Ansatz verwendet wird.

Anstatt den Wert der Objekteigenschaft zu erhalten, die die beiden Klassen eng miteinander verbindet , verwenden Sie das Objekt als Parameter, z

  doSomethingWithProperty() {
     doSomethingWith( this.property ) ;
  }

Wenn die Eigenschaft ein nativer Typ war, z. B. int, verwenden Sie eine Zugriffsmethode und benennen Sie sie für die Problemdomäne, nicht für die Programmierdomäne.

  doSomethingWithProperty( this.daysPerWeek() ) ;

Auf diese Weise können Sie die Kapselung und alle Nachbedingungen oder abhängigen Invarianten beibehalten. Sie können auch die Setter-Methode verwenden, um Vorbedingungen oder abhängige Invarianten beizubehalten. Fallen Sie jedoch nicht in die Falle, diese Setter zu benennen, sondern kehren Sie zur Benennung des Hollywood-Prinzips zurück, wenn Sie das Idiom verwenden.

Martin Spamer
quelle
8

Es ist besser, die Zugriffsmethoden auch innerhalb des Objekts zu verwenden. Hier sind die Punkte, die mir sofort einfallen:

  1. Dies sollte im Interesse der Konsistenz mit Zugriffen von außerhalb des Objekts erfolgen.

  2. In einigen Fällen können diese Zugriffsmethoden mehr als nur den Zugriff auf das Feld ermöglichen. Sie könnten eine zusätzliche Verarbeitung durchführen (dies ist jedoch selten). Wenn dies der Fall ist, würde ein direkter Zugriff auf das Feld bedeuten, dass Ihnen diese zusätzliche Verarbeitung fehlt, und Ihr Programm könnte schief gehen, wenn diese Verarbeitung während dieser Zugriffe immer durchgeführt werden soll.

Aadith Ramia
quelle
8

Wenn Sie mit "puristisch" "die meiste Kapselung" meinen, deklariere ich normalerweise alle meine Felder als privat und verwende dann "this.field" innerhalb der Klasse selbst. Für andere Klassen, einschließlich Unterklassen, greife ich mithilfe der Getter auf den Instanzstatus zu.

Allain Lalonde
quelle
7

Ich habe festgestellt, dass die Verwendung von Setzern / Gettern meinen Code leichter lesbar gemacht hat. Ich mag auch das Steuerelement, das es gibt, wenn andere Klassen die Methoden verwenden und wenn ich die Daten ändere, wird die Eigenschaft gespeichert.

Brendon-Van-Heyzen
quelle
7

Private Felder mit öffentlichen oder geschützten Eigenschaften. Der Zugriff auf die Werte sollte über die Eigenschaften erfolgen und in eine lokale Variable kopiert werden, wenn sie in einer Methode mehrmals verwendet werden. Wenn und NUR, wenn Sie den Rest Ihrer Anwendung so vollständig optimiert, gerockt und auf andere Weise optimiert haben, dass der Zugriff auf Werte durch Durchlaufen der zugehörigen Eigenschaften zu einem Engpass geworden ist (und das wird NIEMALS passieren, wie ich garantiere), sollten Sie überhaupt anfangen zu erwägen, dass etwas anderes als die Eigenschaften ihre Hintergrundvariablen direkt berühren.

.NET-Entwickler können automatische Eigenschaften verwenden, um dies zu erzwingen, da Sie die Entwurfsvariablen zur Entwurfszeit nicht einmal sehen können.

Mel
quelle
7

Es hängt davon ab, ob. Es ist mehr ein Stilproblem als alles andere, und es gibt keine harte Regel.

Steve McLeod
quelle
7

Ich kann mich irren, weil ich Autodidakt bin, aber ich benutze NIEMALS öffentliche Eigenschaften in meinen Java-Klassen, sie sind immer privat oder geschützt, so dass externer Code von Gettern / Setzern abgerufen werden muss. Es ist besser für Wartungs- / Änderungszwecke. Und für Code innerhalb der Klasse ... Wenn die Getter-Methode trivial ist, verwende ich die Eigenschaft direkt, aber ich verwende immer die Setter-Methoden, da ich auf Wunsch leicht Code zu Feuerereignissen hinzufügen kann.

Telcontar
quelle
7

Wenn ich die Eigenschaft nicht bearbeite, verwende ich eine öffentliche Methode, es get_property()sei denn, es handelt sich um einen besonderen Anlass, z. B. ein MySQLi-Objekt in einem anderen Objekt. In diesem Fall mache ich die Eigenschaft einfach öffentlich und bezeichne sie als $obj->object_property.

Innerhalb des Objekts ist es für mich immer $ this-> property.

Ross
quelle
5

Nun, mit der Standardimplementierung der C # 3.0-Eigenschaften scheint die Entscheidung für Sie getroffen zu sein. Sie MÜSSEN die Eigenschaft mit dem (möglicherweise privaten) Eigenschaftssetter festlegen.

Ich persönlich benutze das private Member-Behind nur, wenn dies nicht dazu führen würde, dass das Objekt in einen weniger wünschenswerten Zustand fällt, z. B. beim Initialisieren oder beim Caching / Lazy Loading.

Münze
quelle
5

Ich mag die Antwort von cmcculloh , aber die Antwort von Greg Hurlman scheint die richtigste zu sein . Verwenden Sie immer Getter / Setter, wenn Sie sie von Anfang an verwendet haben und / oder Sie daran gewöhnt sind, mit ihnen zu arbeiten.

Abgesehen davon finde ich persönlich, dass die Verwendung von Getter / Setter das Lesen des Codes und das spätere Debuggen erleichtert.

Robinho
quelle
4

Wie in einigen Kommentaren angegeben: Manchmal sollten Sie, manchmal sollten Sie nicht. Das Tolle an privaten Variablen ist, dass Sie alle Orte sehen können, an denen sie verwendet werden, wenn Sie etwas ändern. Wenn Ihr Getter / Setter etwas tut, das Sie brauchen, verwenden Sie es. Wenn es egal ist, entscheiden Sie.

Der umgekehrte Fall könnte gemacht werden, dass wenn Sie den Getter / Setter verwenden und jemand den Getter / Setter ändert, er alle Stellen analysieren muss, an denen der Getter und der Setter intern verwendet werden, um festzustellen, ob etwas durcheinander kommt.

svrist
quelle