У чому сенс властивостей?


11

Ось декілька аргументів щодо властивостей та моїх аргументів:

Простіший у використанні, ніж написання геттерних та сетер-методів

Пари методів Геттера та сеттера - це кодовий запах. Зробити їх легше писати - це полегшити пропуск тесту з математики, використовуючи форму Scantron і заповнивши всі "C". Об'єкти, що містять лише стан, для збереження не повинні використовувати геттери / сетери, а створювати незмінні об’єкти на час збереження.

Для споживача об'єкта важливо те, що він робить, а не як це робить. Його поведінка - це те, що робить; її стан - це, як це робиться. Якщо ви виявляєте, що дбаєте про стан об'єкта (за винятком стійкості, хоча це також порушує ОО), ви просто не займаєтесь ООП і втрачаєте його переваги.

Вони дають грубі показники ефективності для споживачів

Це щось, що може змінитися в майбутньому для будь-якого майна. Припустимо, у версії 1.0 доступ до PropertyX просто повертає поле. У випуску 1.5, якщо поле є нульовим, PropertyX використовує шаблон Null Object для створення нового об’єкта null. У випуску 2.0 поле отримує подальшу перевірку методом getter у PropertyX.

Оскільки властивість стає все більш складною, показник ефективності використання властивості здається все менш правдивим.

Вони краще, ніж громадські поля

Це правда. Але так є і методи.

Вони представляють принципово інший аспект об'єкта, ніж метод, і всі споживачі об'єкта повинні дбати про це

Ви впевнені, що обидва вищезазначені твердження є правдивими?

Їх легше набрати, чоловіче

Звичайно, вводити текст myObject.Lengthпростіше, ніж набирати текст myObject.Length(), але хіба це не можна було виправити за допомогою синтаксичного цукру?


Навіщо використовувати методи замість властивостей?

  • Немає гарантій виконання. API залишатиметься правдивим, навіть якщо метод стане складнішим. Споживачеві потрібно буде профайлювати свій код, якщо він стикається з проблемами продуктивності, а не покладатися на API-програму Word-of-API.

  • Менше, щоб споживач міркував. Чи має ця власність сетер? Метод впевнений, що ні.

  • Споживач думає від правильного мислення OOP. Як споживач API, мені цікаво взаємодіяти з поведінкою об'єкта. Коли я бачу властивості в API, це дуже схоже на стан. Насправді, якщо властивостей робиться занадто багато, вони навіть не повинні бути властивостями, так що насправді властивості в стані API ARE, як вони здаються споживачам.

  • Програміст API більш глибоко подумає про методи із поверненими значеннями та уникне змінити стан об'єкта в таких методах, якщо це можливо. Наскільки це можливо, слід виконувати відокремлення команд від запитів.


Тож запитую вас, навіщо використовувати властивості замість методів? Більшість пунктів MSDN - це запахи коду і самі по собі, і не належать ні до властивостей, ні до методів.

(Ці думки прийшли до мене після роздумів про CQS.)


5
+1. Властивості - це методи з синтаксисом полів, і це просто не має сенсу.
Неманья Трифунович

23
@Nemanja Trifunovic: Це має сенс, якщо ви писали type GetFoo() void SetFoo()десять тисяч разів. За весь час написання коду C # я ніколи не плутався у власності.
Ред С.

23
Мені звучить так, як ти вже вирішив. У чому питання?
Дін Хардінг

9
@Nemanja Trifunovic: "Геттери і сетери загалом погані" Ви можете повторити це скільки завгодно разів, але це не зробить це правдою. Як щодо пояснення, чому ви вважаєте, що вони погані? Що стосується збоїв SO через введення імені властивості замість основного імені змінної, то неможливо пропустити помилку, враховуючи, що вона призведе до збоїв у програмі, як тільки ви зателефонуєте у власність, і це досить рідко. Коли це трапляється, я точно знаю, що я зробив, щоб викликати це, і я це зафіксував за дві секунди. Я не бачу проблеми.
Ред С.

3
Тільки проходячи повз, щоб вказати @NemanjaTrifunovic, що те, чому методики геттерів та сетер є злісною статтею, досить давнє , про яву і підкреслює слабкість Java : слабкість не має властивостей . (отже, демонструючи занадто багато деталей щодо впровадження) ... кусаючи наш хвіст тут. (це має бути з назвою геттерів і сеттерів погано в Java, тому що ми не маємо про це добре продуманого стандарту )
ZJR

Відповіді:


44

Чому це "методи проти властивостей"? Метод щось робить. Власність - це член об'єкта. Вони абсолютно різні речі, хоча два типи методів, які зазвичай пишуться - геттери та сетери - відповідають властивостям. Оскільки порівнювати властивості з методами взагалі не має сенсу, я вважаю, що ви мали намір поговорити про геттерів / сеттерів.

Пари методів Геттера та сеттера - це кодовий запах.

Не обов’язково, я б заперечував, але в будь-якому випадку це не питання геттерів / сеттерів проти властивостей, а питання, чи потрібно використовувати будь-яке. Також зауважте, що ви можете, наприклад, залишити setXчастину так само, як ви можете створити властивості лише для читання.

Для споживача об'єкта важливо те, що він робить, а не як це робить. Його поведінка - це те, що робить; її стан - це, як це робиться. Якщо ви виявляєте, що дбаєте про стан об'єкта (за винятком стійкості, хоча це також порушує ОО), ви просто не займаєтесь ООП і втрачаєте його переваги.

Дуже сумнівне ставлення. Якщо графічний інтерфейс хоче виводити дані, що зберігаються з а DataStuffManagerImpl, йому потрібно якось отримати це число з нього (і ні, забиття половини програми в клас віджетів не є опцією).

Оскільки властивість стає все більш складною, показник ефективності використання властивості здається все менш правдивим.

[Методи] Немає гарантій ефективності. API залишатиметься правдивим, навіть якщо метод стане складнішим. Споживачеві потрібно буде профайлювати свій код, якщо він стикається з проблемами продуктивності, а не покладатися на API-програму Word-of-API.

Майже у всіх випадках вся логіка валідації тощо все ще є ефективно O (1) або інакше не вагомою вартістю. Якщо ні, можливо, ви зайшли занадто далеко і настав час для змін. А getX()метод зазвичай трактується також як дешевий!

Звичайно, набрати myObject.Length простіше, ніж набрати myObject.Length (), але не вдалося це виправити за допомогою трохи синтаксичного цукру?

Властивості полягають у тому , що синтаксичний цукор.

Менше, щоб споживач міркував. Чи має ця власність сетер? Метод впевнений, що ні.

"Чи є сетер для цього геттера?" Однакова різниця.

Програміст API більш глибоко подумає про методи із поверненими значеннями та уникне змінити стан об'єкта в таких методах, якщо це можливо. Наскільки це можливо, слід виконувати відокремлення команд від запитів.

Я не впевнений, що ти тут намагаєшся нам сказати. Що стосується властивостей, існує ще сильніший неписаний закон не викликати побічних ефектів.


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

Пари методів Геттера та сеттера - це кодовий запах.

Це хибне припущення і абсолютно невірне. Методи отримання / встановлення - це спосіб інкапсуляції члена даних і жодним чином не є "запахом коду". Я дуже ненавиджу те, як деякі люди кидають термін "кодовий запах", але все одно ...

Це щось, що може змінитися в майбутньому для будь-якого майна. Припустимо, у версії 1.0 доступ до PropertyX просто повертає поле. У випуску 1.5, якщо поле є нульовим, PropertyX використовує шаблон Null Object для створення нового об’єкта null. У випуску 2.0 поле отримує подальшу перевірку методом getter у PropertyX.

Оскільки властивість стає все більш складною, показник ефективності використання властивості здається все менш правдивим.

Здається, що це погано розроблений API, я не бачу, як це є синтаксисом властивості.

Властивості в C # були просто синтаксичним цукром за дуже поширеною схемою, яка полегшила наше життя програмістам. Однак у ці дні, якщо ви хочете використовувати прив'язування даних, ви "повинні" використовувати властивості, тому їх зараз трохи більше, ніж синтаксичного цукру. Напевно, я справді просто не згоден ні з одним із ваших моментів, і я не розумію, чому вам не подобається мовна функція, яка безпосередньо підтримує загальну схему.


1
Я збираюся дати щедрості, щоб придумати кращий термін, ніж запах коду. Просто прочитайте книгу про рефакторинг, де вона використовується близько тисячі разів. Це як нігті на дошці.
JeffO

1
@Jeff O: Так, я вважаю, що люди, які, здається, кидають цей термін, як правило, не мають великого досвіду.
Ред С.

6
@Jeff O та @Ed S: IME, "кодовий запах" став тим терміном, який люди використовують, коли вони насправді мають на увазі "мені це не подобається, але в мене насправді немає причини"
Стівен Еверс

3
@SnOrfus: Так, або коли вони дотримуються "релігійних" поглядів, які часто мають мало сенсу на практиці, наприклад "метод ніколи не повинен мати більше X числа рядків" , що, в свою чергу, зазвичай є лише повторенням того, що вони десь читають.
Ред С.

1
Неприйнятне використання методів геттер / сетер є кодом запах, але так само має бути неправильне використання нічого . Навіть у випадках, коли у випадках є вузьке використання, використання таких речей для тих випадків використання не слід вважати запахом коду. Створення сетерів для всього не повинно бути сліпою звичкою, але не варто боятися включати їх, коли це доречно. Необхідно збалансувати корисність для клієнтів того, що вони зможуть змінити стан, а не зможуть у майбутньому з’ясувати, яким був стан раніше (легко, якщо стан є непорушним). Обидва корисні, але код повинен вибрати один.
supercat

10

Ваша передумова неправильна.

Властивості жодним чином не є контрактом на виконання або внутрішньою реалізацією чи будь-яким іншим.
Властивості - це спеціальні пари методів, які семантично представляють атрибут, якщо ви хочете. І таким чином єдиний договір полягає в тому, що майно поводиться так, як ви очікували, що атрибут повинен вести себе.
Якщо я запитую колір об'єкта, я не роблю припущення, чи він отриманий шляхом простого доступу до поля, чи обчислюється він вчасно.
Вся справа в тому, щоб мати можливість розкривати поведінку атрибута за допомогою методів, тоді як це прозоро для споживача інтерфейсу, будь то поле чи аксесуари.

Наявність атрибутів (і фактично приховування їх реалізації, оскільки властивості протиставляються полям) - це потужна декларативна особливість, яка є основою для наявності візуальних інспекторів об'єктів та інших автоматичних генерацій перегляду, для прив'язки даних та багатьох інших корисних речей. І найголовніше - це чітко передає цю інформацію і вашим колегам-програмістам.


6

Споживач думає від правильного мислення OOP. Як споживач API, мені цікаво взаємодіяти з поведінкою об'єкта. Коли я бачу властивості в API, це дуже схоже на стан. Насправді, якщо властивостей робиться занадто багато, вони навіть не повинні бути властивостями, так що насправді властивості в стані API ARE, як вони здаються споживачам.

Власність повинна бути державою. Якщо базовий сеттер або код getter змінюється, щоб значно доповнити обробку, необхідну для встановлення або отримання стану, то це справді вже не властивість, і вам слід замінити його методами. Це залежить від вас як розробника коду.

Поставити занадто багато (скільки занадто багато залежить) коду в сеттер або геттер невірно, але тільки тому, що це можливо, це не привід викидати шаблон у всіх випадках.


6

Одне, чого вам не вистачає, і я не знаю, чи це через незнання, чи ви навмисно нехтуєте цією деталлю, - це властивості ARE.

Коли ви використовуєте синтаксис властивостей C #, компілятор спокійно створює getter і setter методи з метаданими, які повідомляють мови, які розуміють властивості як синтаксичну особливість першого класу, щоб трактувати їх як такі. Це, власне, синтаксичний цукор, про який ви просите. Кілька мов, які можна запустити в CLR, не повністю приховують цю деталь від вас (Boo, якщо мені служить пам'ять, і деякі реалізації Lisp), і ви можете викликати геттерів і сетерів явно.

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

Тепер більш широке питання полягає в тому, чи фактично геттер і сеттер - це хороша річ. Виразно є компроміси; якщо у вас є мутаційні методи, ваш код за своєю суттю менш паралельний, тому що вам зараз доведеться мати справу з проблемами синхронізації потоків. І цілком можливо, що ви ризикуєте порушити Закон Деметера за допомогою мутаційних методів (незалежно від того, чи називаються вони властивостями чи методами getter / setter; вони еквівалентні), оскільки це так зручно робити.

Але іноді це правильно робити. Іноді ваша проблема полягає в тому, щоб забрати дані з якогось джерела, трохи змінити їх, представити оновлені дані користувачеві та зберегти зміни. Ця ідіома добре обслуговується властивостями. Як говориться в статті Аллена Голуба, те, що у геттерів і сетер є проблеми, не означає, що ви ніколи не повинні їх використовувати. (Папугання абстрактних Гуруспек вважається шкідливим). Навіть якщо ви дотримуєтесь підходу до класу / обов'язків / співпрацівників, ви все-таки піддаєте комусь інформацію або презентацію інформації; справа полягає в мінімізації площі поверхні заплутування.

Перевага властивостей полягає в тому, що дуже легко, щоб інший об’єкт скористався ними. Мінус властивостей полягає в тому, що дуже легко змусити їх скористатися іншим об’єктом, і цього не можна легко запобігти.

Мутація об'єкта має сенс на рівні контролера, наприклад, в архітектурі MVC. Це ваш співпрацівець. Ваш погляд також є співробітником, але він не повинен безпосередньо мутувати ваші об'єкти, оскільки він має різні обов'язки. Введення коду презентації у ваші бізнес-об'єкти не обов'язково є правильним способом уникнути ігроків / сетерів.

Рівняння дещо змінюється, якщо ви використовуєте функціональні, а не чисті OO, абстракції, що робить копії об'єкта "запис" із парою змін досить тривіальними, хоча і не безкоштовними. І ей, якщо ви намагаєтеся отримати гарантії продуктивності, властивості, як правило, більш передбачувані, ніж ледача перебудова незмінної колекції.


5

Ще одна важлива причина моєї книги щодо використання властивостей полягає в тому, що вони можуть значно підвищити читабельність.

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

явно набагато менш читабельна, ніж

account.Balance += deposit;

6
За винятком того, що баланс не повинен бути властивістю, оскільки, безумовно, є важлива бізнес-логіка, пов’язана з його зміною (перевірка на овердрафт; стягнення плати за послуги; запис транзакції тощо). Температура, фонове забарвлення тощо)
Кейт Григорій

9
Чому б не рахунок.Депозит (сума)?
xofz

4
@Sam Pearson: +1. Ідеальний приклад того, чому геттери / сетери часто вказують на поганий дизайн.
Nemanja Trifunovic

4

У вас майже протилежна релігійна точка зору :)

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

Для мене властивості - це більш природний та виразний спосіб встановлення та отримання стану об'єкта. Спираючись на непримусові умови кодування - це скоріше "запах коду", ніж все, за що ви критикуєте властивості. Крім того, як говорили інші, придумати погано розроблене використання властивостей та використовувати його недоліки, щоб спробувати і відкинути концепцію властивостей взагалі є вкрай поганою формою. Можливо, ви бачили лише погане використання властивостей і припускаєте, що саме так я думаю, але вам слід зробити більше досліджень, перш ніж стати занадто догматичним.


+1 Це справді використання нерухомості. Чудова відповідь. " Це також означало, що ви можете обмежити доступ до властивостей, зробивши їх захищеними в абстрактному базовому класі, потім перемістивши їх до загальнодоступних або опублікувавши в підкласах. "
Картік Сріенівасан,

Delphi зловживає властивостями рекламної нудоти. Ви не сортуєте список, ви встановлюєте його sorted властивість true. Таким чином, встановивши його, falseви отримаєте оригінальний список. : D Або це перетасовує це випадковим чином? : D Або що завгодно, це просто дурно. Крім того, це чорт повільно порівняно з правильним відсортованим набором. Властивості не погані, але я навчився користуватися ними дуже економно (до тих пір, коли я цілком задоволений геттером та сеттерами; я використовую переважно Java).
maaartinus

1

Однією з причин властивостей, які були введені в Java Beans Framework, було дозволити інтеграцію з IDE - ви можете перетягнути ці компоненти до IDE та редагувати властивості за допомогою редакторів властивостей.

(тоді вони були лише звичайними жителями та сетерами - і визначалися лише конвенцією про іменування - і це справді пахло)

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


1

Ще один кут - вони дійсно прийшли від VB. Пам’ятайте, ще в темні дні 20 століття, коли .NET був задуманий одним із головних акцентів, це була легка заміна VB, щоб ваші програмісти VB могли просто перетягувати речі на веб-форми. VB мав властивості, тому вам потрібно було зберегти цю функцію, щоб перекладати речі правильно.


1
Андерс Гельсберг сконструював C # (та деякі ІР), а також розробив Delphi - який мав властивості.
Jesse C. Slicer

1

Існують щонайменше дві цілі для властивостей:

  • Вони концептуально ідентичні полям, навіть якщо вони реалізовані по- різному. Геттер не повинен змінювати стан об'єкта і не повинен мати побічних ефектів. Сеттер повинен змінювати стан лише способами, концептуально подібними до модифікації поля і не мати інших побічних ефектів.

  • Вони синтаксично ідентичні публічним (можливо лише для читання) полям. Це означає, що публічне поле може бути змінено на властивість, не порушуючи абонентів на рівні джерела.


Так, але зауважте слово "слід". Немає нічого про властивості, які не дають геттерам мати побічні ефекти, і насправді я бачив численні випадки, коли це було так.
Nemanja Trifunovic

1
Зміна суспільного поля до властивості буде порушити сумісність, що споживає код доведеться перекомпілювати - хоча і немодифікована , який я припускаю , що ви хилите :)
MattDavey

@MattDavey: Дякую Це я мав на увазі. Відредаговано.
dimimcha
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.