Ruby bietet diese praktische und bequeme Möglichkeit, Instanzvariablen gemeinsam zu nutzen, indem man Schlüssel wie
attr_accessor :var
attr_reader :var
attr_writer :var
Warum sollte ich attr_reader
oder attr_writer
wählen, wenn ich einfach attr_accessor
verwenden könnte? Hat das etwas mit der Leistung zu tun (was ich bezweifle)? Ich denke, es gibt einen Grund, sonst hätten sie solche Schlüssel nicht gemacht.
Sie können die verschiedenen Accessors verwenden, um jemandem, der Ihren Code liest, Ihre Absicht mitzuteilen und es einfacher zu machen, Klassen zu schreiben, die korrekt funktionieren, egal wie ihre öffentliche API aufgerufen wird.
class Person
attr_accessor :age
...
end
Hier kann ich sehen, dass ich das Alter sowohl lesen als auch schreiben kann.
class Person
attr_reader :age
...
end
Hier kann ich sehen, dass ich das Alter nur lesen darf. Stellen Sie sich vor, dass es vom Konstruktor dieser Klasse gesetzt wird und danach konstant bleibt. Wenn es einen Mutator (Schreiber) für das Alter gäbe und die Klasse in der Annahme geschrieben würde, dass sich das Alter, wenn es einmal gesetzt ist, nicht mehr ändert, dann könnte ein Fehler entstehen, wenn der Code diesen Mutator aufruft.
Aber was geschieht hinter den Kulissen?
Wenn Sie schreiben:
attr_writer :age
Das wird übersetzt in:
def age=(value)
@age = value
end
Wenn Sie schreiben:
attr_reader :age
Das wird übersetzt in:
def age
@age
end
Wenn Sie schreiben:
attr_accessor :age
Das wird übersetzt in:
def age=(value)
@age = value
end
def age
@age
end
Wenn man das weiß, kann man auch anders darüber nachdenken: Wenn Sie die attr_...-Helfer nicht hätten und die Accessoren selbst schreiben müssten, würden Sie dann mehr Accessoren schreiben, als Ihre Klasse braucht? Würden Sie z. B. auch eine Methode schreiben, die das Schreiben von age ermöglicht, wenn es nur gelesen werden muss?
Nicht alle Attribute eines Objekts sind dafür gedacht, direkt von außerhalb der Klasse gesetzt zu werden. Autoren für alle Ihre Instanzvariablen zu haben, ist im Allgemeinen ein Zeichen für schwache Kapselung und eine Warnung, dass Sie zu viel Kopplung zwischen Ihren Klassen einführen.
Ein praktisches Beispiel: Ich habe ein Designprogramm geschrieben, in dem man Elemente in Containern ablegt. Das Element hatte attr_reader :container
, aber es machte keinen Sinn, einen Writer anzubieten, da sich der Container des Elements nur dann ändern sollte, wenn es in einem neuen Container platziert wird, was auch Positionsinformationen erfordert.
Sie wollen nicht immer, dass Ihre Instanzvariablen von außerhalb der Klasse vollständig zugänglich sind. Es gibt viele Fälle, in denen ein Lesezugriff auf eine Instanzvariable sinnvoll ist, ein Schreibzugriff jedoch nicht (z. B. ein Modell, das Daten aus einer schreibgeschützten Quelle abruft). Es gibt Fälle, in denen man das Gegenteil will, aber mir fallen spontan keine ein, die nicht erfunden sind.