Я не думаю, что есть независимый от языка ответ на этот вопрос, поскольку то, что составляет «свойство», является языковым вопросом, и то, что ожидает вызывающий «свойство», также является языковым вопросом. Я думаю, что самый плодотворный способ думать об этом - думать о том, как это выглядит с точки зрения звонящего.
В C # свойства отличаются тем, что они (условно) пишутся с большой буквы (например, методы), но не содержат скобок (например, переменные общедоступного экземпляра). Если вы видите следующий код, отсутствие документации, что вы ожидаете?
var reciprocalHeading = myHeading.Reciprocal;
Как относительный новичок в C #, но тот, кто читал Руководство по использованию собственности Microsoft , я ожидаю Reciprocal, среди прочего:
- быть логическим членом данных
Headingкласса
- быть недорогим, чтобы звонить, чтобы мне не нужно было кэшировать значение
- отсутствие видимых побочных эффектов
- дать тот же результат, если вызывается дважды подряд
- (возможно) предложить
ReciprocalChangedмероприятие
Из этих предположений (3) и (4), вероятно, являются правильными (предполагая, Headingчто это тип неизменяемого значения, как в ответе Юана ), (1) является дискуссионным, (2) неизвестен, но также дискуссионен, и (5) вряд ли производить семантический смысл (хотя то , что имеет заголовок , возможно , следует иметь HeadingChangedсобытие). Это наводит меня на мысль, что в C # API «получить или вычислить обратное значение» не следует реализовывать как свойство, но особенно если вычисление дешевое и Headingнеизменное, это пограничный случай.
(Тем не менее, обратите внимание, что ни одна из этих проблем не имеет никакого отношения к тому, создает ли вызов свойства новый экземпляр , даже (2). Создание объектов в CLR само по себе довольно дешево.)
В Java свойства являются соглашением именования методов. Если я увижу
Heading reciprocalHeading = myHeading.getReciprocal();
мои ожидания аналогичны приведенным выше (если они изложены менее четко): я ожидаю, что звонок будет дешевым, идемпотентным и не будет иметь побочных эффектов. Однако вне платформы JavaBeans концепция «свойства» не так уж и значима в Java, и, в частности, при рассмотрении неизменяемого свойства, не имеющего соответствующего setReciprocal(), getXXX()соглашение теперь несколько старомодно. Из Effective Java , второе издание (уже более восьми лет):
Методы, которые возвращают booleanнефункцию или атрибут объекта, для которого они вызваны, обычно именуются существительным, именной или глагольной фразой, начинающейся с глагола get…. Существует вокальный контингент, который утверждает, что только третья форма (начиная с get) является приемлемой, но для этого утверждения мало оснований. Первые две формы обычно приводят к более читаемому коду… (с. 239)
В современном, более свободном API я бы ожидал увидеть
Heading reciprocalHeading = myHeading.reciprocal();
- что еще раз говорит о том, что вызов дешев, идемпотентен и не имеет побочных эффектов, но ничего не говорит о том, выполняется ли новый расчет или создается новый объект. Это хорошо; в хорошем API, мне все равно.
В Ruby нет такой вещи как собственность. Есть «атрибуты», но если я увижу
reciprocalHeading = my_heading.reciprocal
У меня нет непосредственного способа узнать, обращаюсь ли я к переменной экземпляра с @reciprocalпомощью attr_readerили с помощью простого метода доступа, или я вызываю метод, который выполняет дорогостоящие вычисления. Тот факт, что имя метода является простым существительным, хотя, скорее, чем, скажем calcReciprocal, предполагает, опять же, что вызов, по крайней мере, дешево и, вероятно, не имеет побочных эффектов.
В Scala соглашение об именах заключается в том, что методы с побочными эффектами принимают скобки, а методы без них - нет, но
val reciprocal = heading.reciprocal
может быть любым из:
// 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 = …
(Обратите внимание, что Scala допускает различные вещи, которые, тем не менее, не поощряются руководством по стилю . Это одно из моих главных раздражений в Scala.)
Отсутствие скобок говорит мне, что у звонка нет побочных эффектов; имя, опять же, предполагает, что звонок должен быть относительно дешевым. Кроме того, мне все равно, как это приносит мне ценность.
Короче говоря: знайте язык, который вы используете, и знайте, чего ожидают другие программисты от вашего API. Все остальное - деталь реализации.
Headingнеизменный тип иreciprocalвозвращающий новый,Headingявляется хорошей практикой "ямы успеха". (с оговоркой при двух вызовахreciprocalдолжен возвращать «одно и то же», то есть они должны пройти тест на равенство.)