Ich glaube nicht, dass es eine sprachunabhängige Antwort darauf gibt, da das, was ein „Eigentum“ ausmacht, eine sprachspezifische Frage ist und was ein Anrufer eines „Eigentums“ erwartet, auch eine sprachspezifische Frage ist. Ich denke, die fruchtbarste Art, darüber nachzudenken, besteht darin, darüber nachzudenken, wie es aus Sicht des Anrufers aussieht.
In C # unterscheiden sich Eigenschaften dadurch, dass sie (konventionell) groß geschrieben werden (wie Methoden), aber keine Klammern (wie öffentliche Instanzvariablen) enthalten. Was erwarten Sie, wenn der folgende Code ohne Dokumentation angezeigt wird?
var reciprocalHeading = myHeading.Reciprocal;
Als relativer C # -Anfänger, der jedoch die Microsoft Property Usage Guidelines gelesen hat , würde ich Reciprocal
unter anderem Folgendes erwarten :
- ein logisches Datenelement der
Heading
Klasse sein
- kostengünstig anrufen, sodass ich den Wert nicht zwischenspeichern muss
- es fehlen beobachtbare Nebenwirkungen
- Das gleiche Ergebnis erzielen, wenn zweimal hintereinander aufgerufen wird
- (vielleicht) eine
ReciprocalChanged
Veranstaltung anbieten
Von diesen Annahmen sind (3) und (4) wahrscheinlich richtig (unter der Annahme, dass Heading
es sich um einen unveränderlichen Wertetyp handelt, wie in Ewans Antwort ), (1) ist umstritten, (2) ist unbekannt, aber auch umstritten, und (5) ist unwahrscheinlich machen semantischen Sinn (obwohl , was hat eine Überschrift vielleicht haben sollte HeadingChanged
Ereignis). Dies legt für mich den Schluss nahe, dass in einer C # -API "Get or Calculate the Reciprocal" nicht als Eigenschaft implementiert werden sollte. Insbesondere, wenn die Berechnung billig und Heading
unveränderlich ist, handelt es sich um einen Grenzfall.
(Beachten Sie jedoch, dass keine dieser Bedenken damit zu tun hat, ob durch den Aufruf der Eigenschaft eine neue Instanz erstellt wird , nicht einmal (2). Das Erstellen von Objekten in der CLR an sich ist recht kostengünstig.)
In Java sind Eigenschaften eine Namenskonvention für Methoden. Wenn ich sehe
Heading reciprocalHeading = myHeading.getReciprocal();
Meine Erwartungen sind ähnlich wie die oben genannten (wenn auch weniger explizit dargelegt): Ich erwarte, dass der Anruf billig, idempotent und ohne Nebenwirkungen ist. Außerhalb des JavaBeans-Frameworks ist das Konzept einer "Eigenschaft" in Java jedoch nicht so aussagekräftig, und insbesondere, wenn eine unveränderliche Eigenschaft ohne Entsprechung betrachtet wird setReciprocal()
, ist die getXXX()
Konvention inzwischen etwas altmodisch. Aus Effective Java , zweite Ausgabe (bereits über acht Jahre alt):
Methoden, die eine Nichtfunktion boolean
oder ein Attribut des Objekts zurückgeben, für das sie aufgerufen werden, werden normalerweise mit einem Substantiv, einer Substantivphrase oder einer Verbphrase, die mit dem Verb beginnt, benannt get
. Es gibt ein Stimmkontingent, das behauptet, dass nur die dritte Form (beginnend mit get
) akzeptabel ist, aber es gibt wenig Grundlage für diese Behauptung. Die ersten beiden Formen führen normalerweise zu besser lesbarem Code… (S. 239)
Eine zeitgemäße, flüssigere API würde ich also erwarten
Heading reciprocalHeading = myHeading.reciprocal();
- was wiederum darauf hindeuten würde, dass der Anruf billig, idempotent und ohne Nebenwirkungen ist, aber nichts darüber aussagen würde, ob eine neue Berechnung durchgeführt oder ein neues Objekt erstellt wird. Das ist in Ordnung; In einer guten API sollte es mich nicht interessieren.
In Ruby gibt es keine Immobilien. Es gibt "Attribute", aber wenn ich sehe
reciprocalHeading = my_heading.reciprocal
Ich habe keine unmittelbare Möglichkeit zu wissen, ob ich @reciprocal
über eine attr_reader
oder eine einfache Accessormethode auf eine Instanzvariable zugreife oder ob ich eine Methode aufrufe, die eine teure Berechnung durchführt. Die Tatsache, dass der Methodenname ein einfaches Substantiv ist calcReciprocal
, lässt jedoch nicht sagen , dass der Aufruf zumindest billig ist und wahrscheinlich keine Nebenwirkungen hat.
In Scala ist die Namenskonvention, dass Methoden mit Nebenwirkungen Klammern verwenden und Methoden ohne Klammern
val reciprocal = heading.reciprocal
könnte sein:
// immutable public value initialized at creation time
val reciprocal: Heading = …
// immutable public value initialized on first use
lazy val reciprocal: Heading = …
// public method, probably recalculating on each invocation
def reciprocal: Heading = …
// as above, with parentheses that, by convention, the caller
// should only omit if they know the method has no side effects
def reciprocal(): Heading = …
(Beachten Sie, dass Scala ermöglicht verschiedene Dinge , die dennoch sind entmutigt durch den Style - Guide . Dies ist eine meiner großen Belästigungen mit Scala ist.)
Das Fehlen von Klammern sagt mir, dass der Anruf keine Nebenwirkungen hat. der name legt wiederum nahe, dass der anruf relativ billig sein sollte. Darüber hinaus ist es mir egal, wie es mir den Wert bringt.
Kurz gesagt: Kennen Sie die Sprache, die Sie verwenden, und wissen Sie, welche Erwartungen andere Programmierer an Ihre API stellen. Alles andere ist ein Implementierungsdetail.
Heading
unveränderlichen Typ zu haben undreciprocal
einen neuen zurückzugebenHeading
. (mit der Einschränkung bei den beiden Aufrufenreciprocal
sollte "das Gleiche" zurückgeben, dh sie sollten den Gleichheitstest bestehen.)