Какой смысл в свойствах?

11

Вот некоторые аргументы для свойств и мои контраргументы:

Проще использовать, чем писать методы получения и установки

Пары методов получения и установки являются запахом кода. Упростить их написание - это все равно, что облегчить прохождение математического теста, используя форму Scantron и заполнив все буквы "С". Объекты, которые содержат только состояние, для персистентности, не должны использовать геттеры / сеттеры и должны создавать неизменяемые объекты во время персистентности.

Для потребителя объекта важно то, что он делает, а не то, как он это делает. Его поведение - это то, что он делает; его состояние таково, как оно это делает. Если вы заботитесь о состоянии объекта (за исключением постоянства, хотя это также нарушает ОО), вы просто не выполняете ООП и теряете его преимущества.

Они дают приблизительное представление о производительности для потребителей

Это то, что может измениться в будущем для любого данного свойства. Предположим, что в версии 1.0 доступ к PropertyX просто возвращает поле. В версии 1.5, если поле имеет значение null, PropertyX использует шаблон Null Object для создания нового нулевого объекта. В версии 2.0, поле получает дальнейшую проверку методом getter в PropertyX.

По мере того как свойство становится все более и более сложным, показатель эффективности использования свойства кажется все менее правдивым.

Они лучше публичных полей

Это правда. Но методы тоже.

Они представляют принципиально иной аспект объекта, чем метод, и все потребители объекта должны заботиться об этом

Вы уверены, что оба вышеприведенных утверждения верны?

Их легче набирать, чувак

Конечно, печатать myObject.Lengthлегче, чем печатать myObject.Length(), но разве это нельзя исправить небольшим синтаксическим сахаром?


Зачем использовать методы вместо свойств?

  • Нет гарантий производительности. API останется правдивым, даже если метод станет более сложным. Потребитель должен будет профилировать свой код, если он сталкивается с проблемами производительности, и не полагаться на слово API.

  • Меньше для потребителя думать. Есть ли у этого свойства установщик? Метод, конечно, нет.

  • Потребитель думает с правильного мышления ООП. Как потребитель API я заинтересован во взаимодействии с поведением объекта. Когда я вижу свойства в API, это выглядит как состояние. Фактически, если свойства делают слишком много, они даже не должны быть свойствами, поэтому на самом деле свойства в состоянии API ARE таковы, какими они кажутся потребителям.

  • Программист API будет более глубоко задумываться о методах с возвращаемыми значениями и по возможности избегать изменения состояния объекта в таких методах. Отделение команд от запросов должно выполняться везде, где это возможно.


Поэтому я спрашиваю вас, зачем использовать свойства вместо методов? Большинство точек в MSDN являются запахами кода сами по себе и не принадлежат ни свойствам, ни методам.

(Эти мысли пришли ко мне после размышлений о CQS.)

xofz
источник
5
+1. Свойства - это методы с синтаксисом полей, и это просто не имеет смысла.
Неманья Трифунович
23
@Nemanja Trifunovic: Это имеет смысл, если вы написали type GetFoo() void SetFoo()десять тысяч раз. За все время написания кода на C # меня никогда не смущало свойство.
Эд С.
23
Похоже, ты уже принял решение. Что за вопрос?
Дин Хардинг
9
@Nemanja Trifunovic: «Геттеры и сеттеры, как правило, плохие». Вы можете повторять это столько раз, сколько захотите, но это не поможет. Как насчет объяснения, почему вы думаете, что они плохие? Поскольку SO вылетает из-за ввода имени свойства вместо имени базовой переменной, невозможно пропустить ошибку, поскольку она вылетит из программы, как только вы вызовете свойство, и это довольно редко. Когда это случается, я точно знаю, что я сделал, чтобы вызвать это, и я исправляю это за две секунды. Я не вижу проблемы.
Эд С.
3
Просто проходя мимо, чтобы указать @NemanjaTrifunovic на то, что методы «Почему методы получения и установки - это зло» довольно стары , посвящены Java и подчеркивают слабость Java : слабость отсутствия свойств . (следовательно, демонстрируя слишком много деталей реализации)… кусая наш хвост здесь. (он должен называться геттеры и сеттеры плохи в Java, потому что у нас нет чертовски хорошо продуманных стандартов о них )
ZJR

Ответы:

44

Почему это "методы против свойств"? Метод что-то делает. Свойство, ну, в общем, член объекта. Это совершенно разные вещи, хотя обычно пишутся два вида методов - геттеры и сеттеры. Поскольку сравнение свойств с методами в целом не имеет смысла, я предполагаю, что вы хотели поговорить о методах получения / установки.

Пары методов получения и установки являются запахом кода.

Не обязательно, я бы поспорил, но в любом случае это не вопрос получения / установки или свойства, а вопрос, следует ли использовать любой из них. Также обратите внимание, что вы можете, например, опустить setXдеталь так же, как вы можете сделать свойства только для чтения.

Для потребителя объекта важно то, что он делает, а не то, как он это делает. Его поведение - это то, что он делает; его состояние таково, как оно это делает. Если вы заботитесь о состоянии объекта (за исключением постоянства, хотя это также нарушает ОО), вы просто не выполняете ООП и теряете его преимущества.

Весьма сомнительное отношение. Если GUI хочет выводить данные, хранящиеся в a DataStuffManagerImpl, ему нужно каким-то образом получить это число (и нет, переполнение половины приложения в классе виджетов не вариант).

По мере того как свойство становится все более и более сложным, показатель эффективности использования свойства кажется все менее правдивым.

[Методы есть] Нет никаких гарантий производительности. API останется правдивым, даже если метод станет более сложным. Потребитель должен будет профилировать свой код, если он сталкивается с проблемами производительности, и не полагаться на слово API.

Практически во всех случаях вся логика валидации и т. Д. По-прежнему эффективно равна O (1) или иным образом незначительна по стоимости. Если нет, возможно, вы зашли слишком далеко, и пришло время для перемен. И getX()метод обычно рассматривается как дешевый!

Конечно, набирать myObject.Length проще, чем набирать myObject.Length (), но разве это нельзя исправить с помощью небольшого синтаксического сахара?

Свойства являются , что синтаксический сахар.

Меньше для потребителя думать. Есть ли у этого свойства установщик? Метод, конечно, нет.

"Есть ли сеттер для этого геттера?" Такая же разница.

Программист API будет более глубоко задумываться о методах с возвращаемыми значениями и по возможности избегать изменения состояния объекта в таких методах. Отделение команд от запросов должно выполняться везде, где это возможно.

Я не уверен, что вы пытаетесь сказать нам здесь. Для свойств есть еще более сильный неписаный закон, не вызывающий побочных эффектов.

ChrisF
источник
3
+1, и это не неписаный закон. В руководстве по использованию собственности на MSDN написано это со многими другими. Я думаю, что ОП должен пройти через них, чтобы прояснить многие сомнения. И я не могу опубликовать ссылку здесь, так как пишу это со своего телефона, но рекомендации должны быть легко найдены.
дециклон
@delnan: Свойства не тот синтаксический сахар. Свойства могут рассматриваться как поля (они могут использоваться как цель назначения, если у них есть установщик). Методы не могут.
xofz
1
@SamPearson: obj.x = yкарты obj.setX(y)и obj.xкарты для obj.getX(). Как это отличается?
1
@SamPearson вы можете изменить видимость установщика свойства и получателя независимо друг от друга. Я использую это все время с моими объектами Entity Framework: мои сеттеры защищены (поэтому только среда может установить значение). Поэтому вполне допустимо сказать int length = myObject.Length, не используя myObject.Length = 10
Майкл Браун,
19

Пары методов получения и установки являются запахом кода.

Это ошибочное предположение и совершенно неверное. Методы Get / Set - это способ инкапсулировать элемент данных и ни в коем случае не «запах кода». Я действительно ненавижу то, как некоторые люди используют термин «запах кода», но все равно ...

Это то, что может измениться в будущем для любого данного свойства. Предположим, что в версии 1.0 доступ к PropertyX просто возвращает поле. В версии 1.5, если поле имеет значение null, PropertyX использует шаблон Null Object для создания нового нулевого объекта. В версии 2.0, поле получает дальнейшую проверку методом getter в PropertyX.

По мере того как свойство становится все более и более сложным, показатель эффективности использования свойства кажется все менее правдивым.

Похоже, плохо разработанный API, я не понимаю, как это вина синтаксиса свойства.

Свойства в C # были просто синтаксическим сахаром для очень распространенного паттерна, который немного облегчил нашу жизнь программистов. Однако, в наши дни, если вы хотите использовать привязку данных, вы должны использовать свойства, поэтому они теперь немного больше, чем синтаксический сахар. Наверное, я просто не согласен ни с одним из ваших замечаний, и я не понимаю, почему вам не нравится языковая функция, которая напрямую поддерживает общий шаблон.

Эд С.
источник
1
Я собираюсь дать награду, чтобы придумать лучший термин, чем запах кода. Просто прочитайте книгу о рефакторинге, где она используется около тысячи раз. Это как ногти на доске.
Джефф
1
@Джефф О: Да, я нахожу, что люди, которые, кажется, используют этот термин чаще всего, не имеют большого опыта.
Ed S.
6
@Jeff O и @Ed S: IME, «запах кода» стал общепринятым термином, который люди используют, когда они действительно означают «мне это не нравится, но на самом деле у меня нет причины»
Стивен Эверс
3
@SnOrfus: Да, или когда они придерживаются «религиозных» взглядов, которые часто не имеют большого смысла на практике, например, «метод не должен иметь больше, чем X строк» , что, в свою очередь, обычно является просто повторением чего-то, что они где-то читают.
Эд С.
1
Неприемлемое использование методов геттер / сеттер является кодом запах, но так же должно быть неправильное использование ничего . Даже когда вещи имеют узкие варианты использования, использование таких вещей для этих вариантов использования не должно рассматриваться как запах кода. Создание сеттеров для всего не должно быть слепой привычкой, но не следует бояться включать их в случае необходимости. Что необходимо, так это сбалансировать полезность для клиентов возможности изменения состояния по сравнению с возможностью узнать в будущем, каким оно было раньше (легко, если состояние неизменяемое). Оба полезны, но код должен выбрать один.
суперкат
10

Ваша предпосылка неверна.

Свойства никоим образом не являются контрактом на производительность или внутреннюю реализацию или что-либо еще.
Свойства - это специальные пары методов, которые, если хотите, семантически представляют атрибут. И, таким образом, единственный контракт заключается в том, что свойство ведет себя так, как вы ожидаете от атрибута.
Если я спрашиваю о цвете объекта, я не делаю предположений, получен ли он при доступе к простому полю или он рассчитывается только во времени.
Весь смысл в том, чтобы иметь возможность раскрыть поведение атрибута с помощью методов, в то время как он прозрачен для потребителя интерфейса, независимо от того, используете ли вы поле или методы доступа.

Наличие атрибутов (и фактически скрытие их реализации, поскольку свойства противоположны полям) является мощной декларативной функцией, которая является основой для наличия инспекторов визуальных объектов и других автоматических генераций представлений, для привязки данных и многих других полезных вещей. И самое главное, он явно передает эту информацию и вашим коллегам-программистам.

back2dos
источник
6

Потребитель думает с правильного мышления ООП. Как потребитель API я заинтересован во взаимодействии с поведением объекта. Когда я вижу свойства в API, это выглядит как состояние. Фактически, если свойства делают слишком много, они даже не должны быть свойствами, поэтому на самом деле свойства в состоянии API ARE таковы, какими они кажутся потребителям.

Имущество должно быть государством. Если базовый установочный или получающий код изменяется, чтобы существенно добавить к обработке, необходимой для установки или получения состояния, то на самом деле это больше не свойство, и вы должны заменить его методами. Это зависит от вас, как разработчика кода.

Неправильно помещать слишком много (как много, слишком много) кода в установщик или получатель, но просто потому, что это возможно, не является причиной для исключения шаблона во всех случаях.

ChrisF
источник
6

Одна вещь, которую вы упускаете, и я не знаю, происходит ли это из-за незнания или вы намеренно пропускаете эту деталь, это то, что свойства - это методы.

Когда вы используете синтаксис свойств C #, компилятор незаметно создает методы getter и setter с метаданными, которые сообщают языкам, которые понимают свойства как первоклассную синтаксическую функцию, для обработки их как таковых. То есть, фактически, синтаксический сахар, который вы просите. Некоторые языки, которые могут быть запущены в CLR, не полностью скрывают эту деталь от вас (Boo, если мне не изменяет память, и некоторые реализации Lisp), и вы можете явно вызывать методы получения и установки.

Свойства иногда имеют побочные эффекты, такие как запуск событий уведомлений об изменениях (например, INotifyPropertyChanged) или пометка экземпляра класса как грязного. Вот где у них есть реальная ценность, хотя их создание - немного больше работы (кроме Boo, в котором есть синтаксические макросы).

Теперь, более широкий вопрос заключается в том, являются ли методы получения и установки действительно хорошими. Есть явно компромиссы; если у вас есть методы-мутаторы, ваш код по своей природе менее параллелизуем, потому что теперь вам приходится иметь дело с проблемами синхронизации потоков. И вполне возможно, что вы рискуете нарушить закон Деметры, используя методы мутатора (будь то свойства или методы получения / установки; они эквивалентны), потому что это чертовски удобно делать.

Но иногда это правильно. Иногда ваша проблема состоит в том, чтобы получить данные из какого-либо источника, немного изменить их, представить обновленные данные пользователю и сохранить изменения. Эта идиома хорошо обслуживается свойствами. Как говорится в статье Аллена Холуба, то , что у получателей и установщиков есть проблемы, не означает, что вы никогда не должны их использовать. (Попугай абстрактного гуруспика считается вредным). Даже если вы следуете подходу Класс / Обязанности / Коллабораторы, вы все равно в конечном итоге предоставляете кому-либо информацию или представление информации; Дело в том, чтобы минимизировать площадь поверхности запутывания.

Достоинством свойств является то, что им легко воспользоваться другим объектом. Недостатком свойств является то, что им легко воспользоваться другими объектами, и вы не можете легко предотвратить это.

Мутация объектов имеет смысл на уровне контроллера, например, в архитектуре MVC. Это твой сотрудник. Ваше мнение также является соавтором, но оно не должно напрямую изменять ваши объекты, потому что у него разные обязанности. Внедрение кода презентации в ваши бизнес-объекты также не обязательно является правильным способом избежать методов получения / установки.

Уравнение немного меняется, если вы используете функциональные, а не чистые OO-абстракции, что обычно делает создание копий объекта «запись» с парой изменений довольно тривиальным, хотя и не бесплатным. И, эй, если вы пытаетесь получить гарантии производительности, свойства, как правило, более предсказуемы, чем ленивая перестройка неизменной коллекции.

JasonTrue
источник
5

Еще одна важная причина использования свойств в моей книге заключается в том, что они могут значительно улучшить читаемость.

account.setBalance(Account.getBalance()+deposit);

явно гораздо менее читабельным, чем

account.Balance += deposit;
apoorv020
источник
6
За исключением того, что Balance не должен быть свойством, потому что с его изменением обязательно будет существенная бизнес-логика (проверьте на овердрафт; начисление платы за обслуживание; запись транзакции и т. Д.). Ваша точка читаемости полностью действительна, если применяется к другому примеру ( Температура, фоновый цвет и т. Д.)
Кейт Грегори
9
Почему не аккаунт. Депозит (сумма)?
xofz
4
@ Сэм Пирсон: +1. Прекрасный пример того, почему геттеры / сеттеры часто указывают на плохой дизайн.
Неманя Трифунович
4

У вас есть почти противоположная религиозная точка зрения для меня :)

Когда я перешел из Delphi в Java, отсутствие свойств было огромным оскорблением для меня. Я привык декларировать свойство и либо указывать его непосредственно на приватную переменную, либо писать (защищенный) метод получения и установки, а затем «подключать» их к свойству. Это инкапсулировало свойство и контролировало, как к нему следует обращаться однозначно. Вы можете иметь свойство только для чтения, которое вычисляет общее количество при обращении к нему, и называть его «Итого», а не «_getTotal ()» или аналогичные метки. Это также означало, что вы можете ограничить доступ к свойствам, сделав их защищенными в абстрактном базовом классе, а затем переместив их в открытый или опубликованный в подклассах.

Для меня свойства являются более естественным и выразительным способом установки и получения состояния объекта. Полагаться на неисполненные соглашения о кодировании - это скорее «запах кода», чем то, за что вы критикуете свойства. Кроме того, как уже говорили другие, придумывать плохо спроектированное использование свойств и использовать его ошибки, чтобы попытаться отклонить концепцию свойств в целом, - это крайне плохая форма. Вполне возможно, что вы видели только плохое использование свойств и предположите, что это так, как я полагаю, но вам следует провести больше исследований, прежде чем стать слишком догматичным.

mcottle
источник
+1 Это действительно реальное использование имущества. Отличный ответ. « Это также означает , что вы могли бы ограничить доступ к свойствам, делая их защиту в абстрактном базовом классе затем переместив их общественности или опубликованы в подклассах. »
Karthik СРИНИВАСАН
Delphi неправильно использует свойства до тошноты. Вы не сортируете список, вы устанавливаете его sorted свойство на true. Так что, установив его, falseвы получите оригинальный список. : D Или это случайно перемешать? : D Или что угодно, это просто глупо. Кроме того, это чертовски медленно по сравнению с правильно отсортированным набором. Свойства не плохие, но я научился использовать их очень экономно (до тех пор, пока я не очень доволен геттерами и сеттерами; я использую в основном Java).
Маартин
1

Одной из причин, по которой свойства были введены в Java Beans Framework, была возможность интеграции с IDE - вы можете перетащить эти компоненты в IDE и редактировать свойства с помощью редакторов свойств.

(тогда они были только обычными получателями и установщиками - и определялись только соглашением об именах - и это действительно пахло)

Сегодня есть еще больше случаев, когда к свойствам обращаются и изменяют не через обычный код - например, во время отладки.

Офир Йоктан
источник
1

Еще один угол - они действительно пришли от VB. Помните, еще в темные дни 20-го века, когда задумывался .NET, одним из основных акцентов было то, что это была простая замена VB, чтобы ваши программисты VB могли просто перетаскивать объекты на веб-формы. У VB были свойства, поэтому вам нужно было сохранить эту функцию для правильного перевода.

Уайетт Барнетт
источник
1
Андерс Хелсберг разработал C # (и некоторые из IL), а также разработал Delphi - который имел свойства.
Джесси С. Слайсер
1

Есть как минимум две цели для свойств:

  • Они концептуально идентичны полям, даже если они реализованы по- разному. Геттер не должен изменять состояние объекта и не должен иметь побочных эффектов. Установщик должен изменять состояние только способами, концептуально подобными модификации поля, и не иметь других побочных эффектов.

  • Они синтаксически идентичны общедоступным (возможно, только для чтения) полям. Это означает, что открытое поле может быть изменено на свойство без прерывания вызывающих на уровне источника.

dsimcha
источник
Да, но обратите внимание на слово «должен». В свойствах нет ничего, что мешало бы получателям иметь побочные эффекты, и на самом деле я видел множество случаев, когда это имело место.
Неманья Трифунович
1
Изменение общественного поля к свойству будет нарушить совместимость, потребляющий код придется перекомпилировать - хотя и не модифицирована , который я предполагаю , что вы клоните :)
MattDavey
@MattDavey: Спасибо. Вот что я имел ввиду. Ред.
дсимча