Я не думаю, что есть независимый от языка ответ на этот вопрос, поскольку то, что составляет «свойство», является языковым вопросом, и то, что ожидает вызывающий «свойство», также является языковым вопросом. Я думаю, что самый плодотворный способ думать об этом - думать о том, как это выглядит с точки зрения звонящего.
В 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
должен возвращать «одно и то же», то есть они должны пройти тест на равенство.)