Як би ви отримали доступ до властивостей об’єкта з допомогою методу об’єкта? [зачинено]


96

Що таке "пуристичний" або "правильний" спосіб отримати доступ до властивостей об'єкта з допомогою об'єктного методу, який не є методом отримання або встановлення?

Я знаю, що ззовні об’єкта ви повинні використовувати геттер / сеттер, але зсередини ви просто зробите:

Java:

String property = this.property;

PHP:

$property = $this->property;

або ви зробите:

Java:

String property = this.getProperty();

PHP:

$property = $this->getProperty();

Вибачте мене, якщо моя Java трохи не працює, минув рік, як я програмував на Java ...

Редагувати:

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

Відповіді:


62

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


не робить нічого іншого в установці, крім встановлення значення властивості як приклад неправильного використання в Java.
euphoria83

1
@ euphoria83 Можливо, але це не заважає цьому статися.
Greg Hurlman

Я згоден з оригінальною відповіддю. Однак пам’ятайте лише, що якщо ви встановлюєте або отримуєте щось приватне всередині класу або об’єкта, вам потрібно переконатися, що getter / setter не є циклічним чи зайвим якимось чином, що спричиняє збій вашого коду. Якщо ви не можете скористатися геттером / сеттером, то зверніться до нього безпосередньо. (Наприклад, ваш геттер / сетер отримує доступ до вторинного (приватного / захищеного) методу для обробки даних.)
Рік Мак Гілліс,

43

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

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


26

Я досить здивований, наскільки одностайними є такі настрої, gettersі сетери прекрасні та хороші. Я пропоную запальну статтю Аллена Голуба " Геттери та сетери - це зло ". Звичайно, заголовок має значення шоку, але автор робить вагомі зауваження.

По суті, якщо у вас є gettersі settersдля кожного приватного поля, ви робите ці поля такими ж загальнодоступними. Вам було б дуже важко змінити тип приватного поля без ефектів пульсацій для кожного класу, який це викликає getter.

Більше того, з суворої точки зору, об'єкти повинні реагувати на повідомлення (методи), що відповідають їхній (сподіваємось) єдиній відповідальності. Переважна більшість gettersі settersне мають сенсу для складових об'єктів; Pen.dispenseInkOnto(Surface)для мене має більше сенсу, ніж Pen.getColor().

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

Однак геттери та сетери є необхідним злом на межі шарів - інтерфейсом користувача, стійкістю тощо. Обмежений доступ до внутрішніх елементів класу, таких як ключове слово друга C ++, захищений доступ до пакетів Java, внутрішній доступ до .NET та шаблон класу друзів, може допомогти вам зменшити видимість gettersта налаштовувачів лише для тих, хто їх потребує.


19

Це залежить від того, як використовується властивість. Наприклад, скажімо, у вас є студентський об’єкт, який має властивість name. Ви можете використати метод Get, щоб витягти ім’я з бази даних, якщо воно ще не отримано. Таким чином ви зменшуєте непотрібні дзвінки до бази даних.

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


Якщо об’єкт Student є об’єктом бізнесу / домену, ви тепер змішуєте деталі інфраструктури. В ідеалі об’єкти бізнесу / домену повинні стосуватися лише логіки бізнесу / домену.
moffdub

Що робити, якщо до геттера додати якийсь логічний вигляд, наприклад: PHP: відкрита функція getName ($ outsideCall = true) {if ($ outsideCall) {$ this-> incrementNameCalled (); } повернути $ this-> name; }, а потім із самого Об’єкта, якщо ви викликали get name, ви можете утримати його від збільшення: PHP: $ name = $ this-> getName (false); Я тут просто переборщую?
cmcculloh

14

PHP пропонує безліч способів впоратися з цим, включаючи магічні методи __getі __set, але я віддаю перевагу явним геттерам і сеттерам. Ось чому:

  1. Перевірку можна розміщувати в установках (і, відповідно, в геттерах)
  2. Intellisense працює з явними методами
  3. Немає сумнівів у тому, чи властивість лише для читання, лише для запису чи читання-запису
  4. Отримання віртуальних властивостей (тобто обчислених значень) виглядає так само, як звичайні властивості
  5. Ви можете легко встановити властивість об’єкта, яка ніколи насправді ніде не визначається, а потім залишається недокументованою

13

Я тут просто переборщую?

Можливо;)

Іншим підходом було б використання приватного / захищеного методу, щоб насправді зробити отримання (кешування / db / і т. Д.), І публічну обгортку для нього, яка збільшує кількість:

PHP:

public function getName() {
    $this->incrementNameCalled();
    return $this->_getName();
}

protected function _getName() {
    return $this->name;
}

а потім всередині самого об’єкта:

PHP:

$name = $this->_getName();

Таким чином, ви все ще можете використовувати цей перший аргумент для чогось іншого (наприклад, надсилання прапорця щодо використання кешованих даних тут чи ні).


12

Мені, мабуть, не вистачає цього, чому б ви використовували геттер всередині об’єкта для доступу до властивості цього об’єкта?

Приймаючи це до свого висновку, геттер повинен викликати геттера, який повинен викликати геттера.

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


Мене підштовхнула та сама потреба, що і ви мали прокоментувати ... Плюс на це відповіли не закрито;)
Egg Vans

8

Пуристичний ОО-спосіб полягає у тому, щоб уникнути обох і слідувати Закону Деметри , використовуючи підхід Tell Don't Ask

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

  doSomethingWithProperty() {
     doSomethingWith( this.property ) ;
  }

Там, де властивість була власним типом, наприклад int, використовуйте метод доступу, називайте його як проблемний домен, а не домен програмування.

  doSomethingWithProperty( this.daysPerWeek() ) ;

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


8

Краще використовувати методи доступу, навіть всередині об'єкта. Ось моменти, які мені відразу спадають на думку:

  1. Це слід робити в інтересах збереження узгодженості з доступом, зробленим ззовні об'єкта.

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


8

Якщо ви маєте на увазі "найбільш інкапсуляцію" під "пуристом", тоді я зазвичай оголошую всі свої поля приватними, а потім використовую "this.field" із самого класу. Для інших класів, включаючи підкласи, я отримую доступ до стану примірника за допомогою геттерів.


7

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


7

Приватні поля із загальнодоступними або захищеними властивостями. Доступ до значень повинен проходити через властивості та копіюватися до локальної змінної, якщо вони будуть використовуватися більше ніж один раз у методі. Якщо і ТІЛЬКИ, якщо у вас решта програми настільки допрацьована, розгойдана та іншим чином оптимізована там, де доступ до значень шляхом перегляду їхніх асоційованих властивостей став вузьким місцем (І цього ніколи не станеться, я гарантую), якщо ви навіть почнете розглянути можливість дозволити будь-що, крім властивостей, безпосередньо торкатися своїх змінних підтримки.

Розробники .NET можуть використовувати автоматичні властивості, щоб забезпечити це, оскільки ви навіть не можете бачити змінні підтримки під час проектування.



7

Я можу помилитися, тому що я автодидакт, але Я НІКОЛИ не користуюся загальнодоступними властивостями у своїх класах Java, вони завжди є приватними або захищеними, тому зовнішній код повинен отримувати доступ з боку геттерів / установників. Це краще для технічного обслуговування / модифікації. А для внутрішнього коду класу ... Якщо метод getter є тривіальним, я використовую властивість безпосередньо, але я завжди використовую методи setter, тому що я міг би легко додати код для запуску подій, якщо хочу.


7

Якщо я не відредагую властивість, я скористаюся загальнодоступним методом, get_property()якщо це не особливий випадок, наприклад, об'єкт MySQLi всередині іншого об'єкта, в цьому випадку я просто опублікую властивість і позначу його як $obj->object_property.

Всередині об'єкта для мене це завжди $ this-> властивість.


5

Що ж, схоже, із типовою реалізацією властивостей C # 3.0 рішення приймається за вас; ВИ ПОВИННІ встановити властивість за допомогою (можливо, приватного) установника властивостей.

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


5

Мені подобається відповідь cmcculloh , але, схоже, найбільш правильною є відповідь Грега Хурлмана . Постійно використовуйте getter / setter, якщо ви почали використовувати їх із самого початку та / або ви звикли працювати з ними.

Окрім того, я особисто вважаю, що використання getter / setter полегшує читання та налагодження коду пізніше.


4

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

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

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