Навіщо використовувати геттери та сетери / аксесуари?


1540

Яка перевага використання геттерів та сетерів - які тільки отримуються та встановлюються - замість того, щоб просто використовувати публічні поля для цих змінних?

Якщо геттери і сетери коли-небудь роблять більше, ніж просто просте отримання / встановлення, я можу це зрозуміти дуже швидко, але я не на 100% зрозуміла, як:

public String foo;

гірше, ніж:

private String foo;
public void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return foo; }

Тоді як перший має набагато менший код котла.


6
@Dean J: Скопіюйте багато інших питань: stackoverflow.com/search?q=getters+setters
Asaph

8
Звичайно, обидва однаково погані, коли об'єкт не потребує змінити властивість. Я вважаю за краще зробити все приватним, а потім додати getters, якщо це корисно, та setters якщо потрібно.
Тордек

26
"Користувачі злі" від Google
OMG Ponies

34
"Аксесоари злі", якщо ви випадково пишете функціональний код або незмінні об'єкти. Якщо вам трапляється писати великі об'єкти, що змінюються, вони дуже важливі.
Крістіан Хейтер

Відповіді:


980

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

Ось деякі з моїх причин:

  • Інкапсуляція поведінки, пов’язаної з отриманням або встановленням властивості - це дозволяє додаткові функції (наприклад, перевірка) додаватися пізніше.
  • Приховування внутрішнього представлення майна під час викриття власності з використанням альтернативного представлення.
  • Ізоляція вашого загальнодоступного інтерфейсу від змін - дозволяє загальнодоступному інтерфейсу залишатися постійним, а впровадження змінюється, не впливаючи на існуючих споживачів.
  • Контроль семантики властивості та управління пам'яттю (розпорядження) властивості - особливо важливий у некерованих середовищах пам'яті (наприклад, C ++ або Objective-C).
  • Надання точки перехоплення налагодження для того, коли властивість змінюється під час виконання - налагодження, коли і де властивість змінено на певне значення, може бути досить складним без цього на деяких мовах.
  • Поліпшена сумісність з бібліотеками, розробленими для роботи проти власників / сеттерів властивостей - глузування, серіалізація та WPF.
  • Дозволити спадкоємцям змінити семантику того, як властивість поводиться та піддається впливу, перекриваючи методи getter / setter.
  • Дозволяє передавати геттер / сетер навколо як лямбда-вирази, а не як значення.
  • Геттери і сетери можуть дозволити різні рівні доступу - наприклад, get може бути загальнодоступним, але набір може бути захищений.

59
+1. Просто додати: Дозволити ледаче завантаження. Дозвіл копіювання під час запису.
NewbiZ

6
@bjarkef: Я вважаю, що publicметоди аксесуарів викликають дублювання коду та відкривають інформацію. Громадські приєднувачі не потрібні для розподілу (серіалізації). У деяких мовах (Java) publicдоступні аксесуари не можуть змінити тип повернення, не порушуючи залежні класи. Більше того, я вважаю, що вони суперечать принципам ОО. Дивіться також: stackoverflow.com/a/1462424/59087
Дейв Джарвіс

15
@sbi: Одне, що купується за допомогою програми встановлення властивостей, навіть у добре розробленій структурі, - це можливість об'єкта сповіщати іншого, коли властивість змінюється.
supercat

22
@supercat: Однак я, як правило, не пропагую публічні дані. Повідомлення інших об'єктів також може бути здійснено за допомогою реальних методів, що забезпечують значну абстракцію простого контейнера даних із (більш-менш) полями загальнодоступних даних. Замість цього plane.turnTo(dir); plane.setSpeed(spd); plane.setTargetAltitude(alt); plane.getBreaks().release();хочу сказати plane.takeOff(alt). Які внутрішні поля даних потрібно змінити, щоб перевести площину в takingOffрежим - це не викликає мого занепокоєння. А про те, які інші об’єкти ( breaks) сповіщає метод, я також не хочу знати.
sbi

8
@BenLee: Я справді не знаю, як ще сказати це. "Accessors" - це лише синонім "getters / setters", і в своїх перших двох коментарях я пояснив, чому це зловживання терміном "OOP". Якщо вам потрібно вступити в нього і безпосередньо маніпулювати державою, це не є об'єктом у сенсі OOP цього терміна.
sbi

480

Оскільки через два тижні (місяці, роки), коли ви зрозумієте, що ваш сетер повинен зробити більше, ніж просто встановити значення, ви також зрозумієте, що властивість використовується безпосередньо в 238 інших класах :-)


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

20
Я можу лише заздрити вам та вашій програмі :-) Ось це, справді, залежить і від вашого програмного забезпечення. Наприклад, Delphi (і C # - я думаю?) Дозволяє визначати властивості як громадяни 1-го класу, де вони можуть читати / записувати поле безпосередньо спочатку, але - якщо вам це потрібно - зробіть це також методами getter / setter. Мучо зручно. Java, на жаль, не - не кажучи вже про стандарт javabeans, який змушує вас також використовувати геттери / сетери.
ChssPly76

14
Хоча це справді є вагомою причиною для використання аксесуарів, зараз багато середовищ програмування та редактори пропонують підтримку для рефакторингу (або в IDE, або як безкоштовні додатки), що дещо зменшує вплив проблеми.
Л.Бушкін

62
звучить як
передзріла

41
Питання, яке вам потрібно задати, коли вам цікаво, чи реалізовувати геттери та сеттери, це: Чому користувачі класу взагалі повинні мати доступ до внутрішніх класів? Не важливо, чи вони це роблять безпосередньо, чи захищені тонким псевдошаром - якщо користувачам потрібно отримати доступ до деталей реалізації, то це знак того, що клас не пропонує достатньо абстракції. Дивіться також цей коментар .
sbi

357

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

Часто згаданою перевагою пар «геттер / сетер» не є. Є твердження, що ви можете змінити реалізацію, і вашим клієнтам не потрібно перекомпілювати. Нібито, сетери дозволяють вам додавати такі функції, як перевірка згодом, і ваші клієнти навіть не повинні про це знати. Однак додавання перевірки сетеру - це зміна його передумов, порушення попереднього договору , яке було, просто кажучи, "ви можете тут все помістити, і ви можете отримати те ж саме пізніше від геттера".

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

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

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

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

class Foo {
public:
    int DaysLeft;
    int ContestantNumber;
};

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

Клієнт : "Що я можу зробити з об'єктом цього класу?"
Дизайнер : "Ви можете читати і писати кілька змінних."
Клієнт : "О ... круто, я думаю?"

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


12
Чудова відповідь (+1). Моя єдина критика полягає в тому, що мені знадобилося кілька прочитань, щоб зрозуміти, наскільки «валідація» в останньому абзаці відрізняється від «перевірки» в перших кількох (які ви викинули в останньому випадку, але просували в першому); коригування формулювання може допомогти в цьому плані.
Гонки легкості по орбіті

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

2
Ключове зауваження полягає в тому, що геттери набагато корисніші, ніж сетери. Геттер може повернути обчислене значення або кешоване обчислене значення. Все, що може зробити сеттер, - це певна перевірка, а потім зміна privateполя. Якщо клас не має сеттерів, його легко зробити непорушним.
Raedwald

7
Е, я думаю, ви не знаєте, що таке інваріант класу. Якщо це нетривіальна структура, це в значній мірі означає, що вона має підтримувати інваріанти, і ніхто просто не може її розробити, не маючи на увазі. "Виникла помилка. Один учасник невірно оновлений." також в значній мірі читається на кшталт "Оновлення члена порушило інваріанти класу". Добре розроблений клас не дозволяє клієнтському коду порушувати його інваріанти.
Р. Мартіньо Фернандес

5
+1 для "німих власників даних має виглядати як німі власники даних" На жаль, сьогодні, здається, всі розробляють усе навколо німих власників даних, і багато фреймворків цього навіть вимагають ...
Joeri Hendrickx

92

Багато людей говорять про переваги геттерів та сетерів, але я хочу грати захисника диявола. Зараз я налагоджую дуже велику програму, де програмісти вирішили зробити все геттером та сеттером. Це може здатися приємним, але його зворотний інженерний кошмар.

Скажіть, ви переглядаєте сотні рядків коду, і вам трапляється таке:

person.name = "Joe";

Це дуже просто фрагмент коду, поки ви не зрозумієте його сеттер. Тепер ви стежите за цим сетером і виявляєте, що він також встановлює person.firstName, person.lastName, person.isHuman, person.hasReallyCommonFirstName, і викликає person.update (), який надсилає запит до бази даних тощо. О, це там, де відбувався витік пам’яті.

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


8
Так. В даний час рефакторинг великої бази даних, і це був кошмар. Геттери і сетери роблять занадто багато, включаючи виклик інших дуже зайнятих геттерів і сетерів, які в кінцевому підсумку зменшують читабельність ні до чого. Перевірка є чудовою причиною для використання аксесуарів, але використання їх робити набагато більше, ніж це, здається, усуває будь-яку потенційну вигоду.
Fadecomic

31
Це аргумент проти синтаксичного цукру, а не проти сетерів загалом.
Філ

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

"Це красиво просто фрагмент коду, поки ви не зрозумієте його сетер" - ей, це був оригінальний пост про Java чи про C #? :)
Honza Zidek

Я повністю згоден з приводу читабельності. Цілком зрозуміло, що відбувається, коли person.name = "Joe";викликається. У способі інформації немає жодної суворості, підсвічування синтаксису показує, що це поле, а рефакторинг простіший (не потрібно рефакторировать два способи та поле). По-друге, всі ті витрачені мозкові цикли, що думають "getIsValid ()" або якщо це "isValid ()" тощо, можна забути. Я не можу придумати жодного разу, коли мене врятував від помилки геттер / сетер.
Буде

53

У чистому об'єктно-орієнтованому світі геттери та сетери - це жахливий анти-шаблон . Прочитайте цю статтю: Геттери / сетери. Зло. Період . Коротше кажучи, вони спонукають програмістів думати про об'єкти як про структури даних, і такий тип мислення є чисто процедурним (як у COBOL або C). В об'єктно-орієнтованій мові немає структур даних, а лише об'єкти, що розкривають поведінку (не атрибути / властивості!)

Ви можете дізнатися більше про них у розділі 3.5 Елегантних об'єктів (моя книга про об’єктно-орієнтоване програмування).


7
Геттери та сетери пропонують анемічну модель домену.
Raedwald

7
Цікава точка зору. Але в більшості програмних контекстів нам потрібні структури даних. Візьмемо приклад "Собака" пов'язаної статті. Так, ви не можете змінити вагу реального собаки, встановивши атрибут ... але new Dog()це не собака. Саме об’єкт зберігає інформацію про собаку. І для цього використання, природно, можна виправити неправильно записану вагу.
Стівен С

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

3
Справжній світ чи ні, Єгор абсолютно прав. Якщо у вас є справді "Структура", і вам не потрібно писати жодного коду, який посилається на нього по імені, помістіть його в хешбел або іншу структуру даних. Якщо вам потрібно написати код для нього, тоді поставте його як член класу і поставте код, який маніпулює цією змінною в тому ж класі, і опустіть сеттер і геттер. PS. Хоча я здебільшого поділяю точку зору Єгора, я вважаю, що коментована квасоля без коду є дещо корисною структурою даних - також інколи потрібні геттери, сеттери не повинні існувати ніколи.
Білл К

1
Я захопився - вся ця відповідь, хоч і правильна і актуальна, не стосується питання безпосередньо. Можливо, він повинен сказати "І сеттери, і getters, і загальнодоступні змінні помиляються" ... Щоб бути абсолютно конкретним, Setters і публічні змінні, що записуються, ніколи не повинні використовуватися, тоді як getters - це майже те саме, що і загальнодоступні змінні, а іноді є необхідним злом але жоден не набагато кращий за інші.
Білл К

52

Причин багато. Моя улюблена - це коли потрібно змінити поведінку або регулювати те, що можна встановити на змінну. Наприклад, скажімо, що у вас був метод setSpeed ​​(int speed). Але ви хочете, щоб ви могли встановити лише максимальну швидкість 100. Ви зробите щось на кшталт:

public void setSpeed(int speed) {
  if ( speed > 100 ) {
    this.speed = 100;
  } else {
    this.speed = speed;
  }
}

А що робити, якщо ВСЯКОГО у вашому коді ви використовували загальнодоступне поле, і тоді ви зрозуміли, що потрібно вказану вище вимогу? Забавляйте, шукаючи публічного поля, а не просто змінюйте свій сетер.

Мої 2 копійки :)


61
Зловживання будь-яким використанням публічного поля не повинно бути таким складним. Зробіть це приватним і дозвольте компілятору їх знайти.
Натан Фелман

12
це правда, звичайно, але навіщо робити це складніше, ніж було призначено. Підхід get / set все ще є кращою відповіддю.
Хардрів

28
@Nathan: Пошук інших звичок не є проблемою. Змінити їх все є.
Graeme Perrow

22
@GraemePerrow змінити їх все - це перевага, а не проблема :( Що робити, якщо у вас був код, який передбачав, що швидкість може бути вище 100 (адже, знаєте, до розірвання контракту це могло!) ( while(speed < 200) { do_something(); accelerate(); })
Р. Martinho Fernandes

29
Це ДУЖЕ поганий приклад! Хтось повинен зателефонувати: myCar.setSpeed(157);і через декілька рядків. speed = myCar.getSpeed();А тепер ... я бажаю вам щасливої ​​налагодження, намагаючись зрозуміти, чому speed==100коли це має бути157
Пьотр Олександр Чмеловський

38

Однією з переваг аксесуарів та мутаторів є те, що ви можете виконати перевірку.

Наприклад, якщо він fooбув загальнодоступним, я міг би його легко встановити, nullі тоді хтось інший міг би спробувати викликати метод на об'єкті. Але його вже немає! За допомогою setFooметоду я міг би переконатися, що цього fooне було встановленоnull .

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


28

Залежить від вашої мови. Ви позначили цю "об'єктно-орієнтовану", а не "Java", тому я хотів би зазначити, що відповідь ChssPly76 залежить від мови. Наприклад, у Python немає причин використовувати геттери та сетери. Якщо вам потрібно змінити поведінку, ви можете скористатись властивістю, яке обертає ґеттер і сетер навколо базового доступу до атрибутів. Щось на зразок цього:

class Simple(object):
   def _get_value(self):
       return self._value -1

   def _set_value(self, new_value):
       self._value = new_value + 1

   def _del_value(self):
       self.old_values.append(self._value)
       del self._value

   value = property(_get_value, _set_value, _del_value)

2
Так, я сказала стільки ж у коментарі під моєю відповіддю. Java - не єдина мова, яка використовує getters / setters як милицю, як і Python - не єдина мова, здатна визначати властивості. Однак головний момент все ж залишається - "власність" - це не те саме "публічне поле".
ChssPly76

1
@jcd - зовсім не так. Ви визначаєте свій "інтерфейс" (публічний API тут буде кращим терміном), відкриваючи ваші загальнодоступні поля. Як тільки це буде зроблено, назад вже не буде. Властивості НЕ поля, оскільки вони надають вам механізм перехоплення спроб доступу до полів (шляхом їх маршрутизації до методів, якщо вони визначені); це, однак, не що інше, як синтаксичний цукор над методами геттера / сеттера. Це надзвичайно зручно, але це не змінює основної парадигми - викриття полів без контролю за доступом до них порушує принцип інкапсуляції.
ChssPly76

14
@ ChssPly76 - я не згоден. У мене так само контроль, як якщо б вони були властивостями, тому що я можу створювати їм властивості, коли мені потрібно. Немає різниці між властивістю, яка використовує getters і setters, і неотримним атрибутом, за винятком того, що сирий атрибут швидший, оскільки він використовує основну мову, а не викликає методи. Функціонально вони однакові. Єдиний спосіб інкапсуляції може бути порушений - це якщо ви вважаєте, що дужки ( obj.set_attr('foo')) за своєю суттю перевершують знаки рівності ( obj.attr = 'foo'). Громадський доступ - це публічний доступ.
jcdyer

1
@jcdyer як багато контролю так, але не настільки читабельність, інші часто помилково припускають, що obj.attr = 'foo'просто встановлює змінну без нічого іншого, що відбувається
Тімо Хуовінен

9
@TimoHuovinen Як це відрізняється від користувача на Java, припускаючи, що obj.setAttr('foo')"просто встановлює змінну без нічого іншого"? Якщо це публічні методи, то це публічний метод. Якщо ви використовуєте його для досягнення якихось побічних ефектів, і він є загальнодоступним, тоді вам краще мати можливість розраховувати на те, що все працює так, ніби трапився лише той призначений побічний ефектусіма іншими деталями реалізації та іншими побічними ефектами, використанням ресурсів, будь-яким іншим) , приховано від проблем користувачів). Це абсолютно не відрізняється від Python. Синтаксис Python для досягнення ефекту просто простіший.
ely

25

Ну, я просто хочу додати, що навіть якщо іноді вони необхідні для інкапсуляції та безпеки ваших змінних / об'єктів, якщо ми хочемо кодувати реальну об'єктно-орієнтовану програму, тоді нам потрібно припинити перенапруження АКСЕСОРІВ , бо іноді ми дуже багато залежимо на них, коли це насправді не потрібно, і це робить майже те саме, що якщо ми розміщуємо змінні загальнодоступними.


24

Дякую, що дійсно прояснило моє мислення. Зараз ось (майже) 10 (майже) вагомих причин НЕ використовувати геттери та сетери:

  1. Коли ви зрозумієте, що вам потрібно зробити більше, ніж просто встановити та отримати значення, ви можете просто зробити поле приватним, яке моментально підкаже вам, куди ви безпосередньо зверталися до нього.
  2. Будь-яка перевірка, яку ви виконуєте там, може бути лише контекстною, що перевірка рідко є на практиці.
  3. Ви можете змінити встановлене значення - це абсолютний кошмар, коли абонент передає вам значення, яке вони [шок жаху] хочуть, щоб ви зберігали ЯК Є.
  4. Ви можете приховати внутрішнє представлення - фантастичне, так що ви переконуєтесь, що всі ці операції симетричні?
  5. Ви захистили свій публічний інтерфейс від змін під аркушами - якщо ви розробляли інтерфейс і не були впевнені, чи прямий доступ до чогось був у порядку, то ви повинні продовжувати розробляти.
  6. Деякі бібліотеки цього очікують, але не багато - рефлексія, серіалізація, макетні об’єкти - все добре працює з публічними полями.
  7. Успадковуючи цей клас, ви можете змінити функціональність за замовчуванням - іншими словами, Ви дійсно можете збити з пантелику абонентів, не тільки приховуючи реалізацію, але і роблячи її непослідовною.

Останні три я просто залишаю (N / A або D / C) ...


11
Я думаю, що вирішальним аргументом є те, що "якщо ви розробляли інтерфейс і не були впевнені, чи був прямий доступ до чогось, тоді ви повинні продовжувати проектувати". Ось найважливіша проблема з геттерами / сеттерами: вони зводять клас до простого контейнера з (більш-менш) публічних полів. У реальному OOP, однак, об'єкт є більше, ніж контейнер полів даних. Він інкапсулює стан та алгоритми для маніпулювання цим станом. У цьому твердженні головне, що стан повинен бути капсульований і маніпулювати лише алгоритмами, що надаються об'єктом.
sbi

22

Я знаю, що це трохи пізно, але я думаю, що є деякі люди, які зацікавлені у виконанні.

Я зробив невеликий тест на продуктивність. Я написав клас "NumberHolder", який, ну, містить цілий ряд. Ви можете прочитати цілий Integer, використовуючи метод getter, anInstance.getNumber()або безпосередньо скориставшись цим номером за допомогою anInstance.number. Моя програма читає число 1 000 000 000 разів обома способами. Цей процес повторюється п’ять разів і друкується час. У мене такий результат:

Time 1: 953ms, Time 2: 741ms
Time 1: 655ms, Time 2: 743ms
Time 1: 656ms, Time 2: 634ms
Time 1: 637ms, Time 2: 629ms
Time 1: 633ms, Time 2: 625ms

(Час 1 - це прямий шлях, Час 2 - отримувач)

Розумієте, геттер (майже) завжди трохи швидший. Потім я спробував з різною кількістю циклів. Замість 1 мільйона я використав 10 мільйонів та 0,1 мільйона. Результати:

10 мільйонів циклів:

Time 1: 6382ms, Time 2: 6351ms
Time 1: 6363ms, Time 2: 6351ms
Time 1: 6350ms, Time 2: 6363ms
Time 1: 6353ms, Time 2: 6357ms
Time 1: 6348ms, Time 2: 6354ms

З 10 мільйонами циклів, часи майже однакові. Ось 100 тисяч (0,1 мільйона) циклів:

Time 1: 77ms, Time 2: 73ms
Time 1: 94ms, Time 2: 65ms
Time 1: 67ms, Time 2: 63ms
Time 1: 65ms, Time 2: 65ms
Time 1: 66ms, Time 2: 63ms

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


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

16

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

Думайте просто, легко, додайте складності, коли це потрібно.

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

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


16

Ми використовуємо геттерів та сеттерів:

  • для повторного використання
  • виконувати перевірку на пізніших етапах програмування

Методи геттера та сетера - це публічні інтерфейси для доступу до членів приватного класу.


Мантра інкапсуляції

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

Методи Геттера: Ми можемо отримати доступ до приватних змінних.

Методи встановлення: Ми можемо змінювати приватні поля.

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

  • краще;
  • безпечніший; і
  • швидше.

Будь-де можна використовувати значення, метод, який повертає це значення, може бути доданий. Замість:

int x = 1000 - 500

використання

int x = 1000 - class_name.getValue();

З точки зору мирян

Представництво класу "Особа"

Припустимо, нам потрібно зберігати деталі цього Person. Це Personмає поле name, ageі sex. Робити це передбачає створення методів name, ageі sex. Тепер, якщо нам потрібно створити іншу людину, виникає необхідність створити методи для name, ageі sexзнову.

Замість цього ми можемо створити боб class(Person)методами геттера та сетера. Тож завтра ми можемо просто створювати об’єкти цього Біна, class(Person class)коли нам потрібно додати нову людину (див. Рисунок). Таким чином, ми повторно використовуємо поля та методи класу квасолі, що набагато краще.


15

Я витратив досить довгий час на роздуми над випадком Java, і я вважаю, що справжні причини:

  1. Код до інтерфейсу, а не реалізація
  2. Інтерфейси задають лише методи, а не поля

Іншими словами, єдиний спосіб вказати поле в інтерфейсі - це надання методу написання нового значення та методу зчитування поточного значення.

Ці методи - сумнозвісний геттер і сетер ...


1
Гаразд, друге питання; у випадку, коли це проект, коли ви нікому не експортуєте джерело, і ви маєте повний контроль над джерелом ... чи отримуєте ви щось із гетерів та сеттерів?
Дін J

2
У будь-якому нетривіальному проекті Java вам потрібно кодувати інтерфейси, щоб зробити речі керованими та перевірятими (продумуйте макети та проксі-об'єкти). Якщо ви використовуєте інтерфейси, вам потрібні геттери та сетери.
Thorbjørn Ravn Andersen

15

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

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

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

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

    protected YourType _yourName = null;
    public YourType YourName{
      get
      {
        if (_yourName == null)
        {
          _yourName = new YourType();
          return _yourName;
        }
      }
    }

Тож, чи отримує виклик сетер?
icc97

Я додав зразок коду того, як я це робив у минулому - по суті, ви зберігаєте фактичний клас у захищеному члені, а потім повертаєте цей захищений член у get accessor, ініціалізуючи його, якщо він не ініціалізований.
quillbreaker


13

Один аспект, який я пропустив у відповідях поки що, специфікація доступу:

  • для членів у вас є лише одна специфікація доступу як для налаштування, так і для отримання
  • для сеттерів та метеорологів ви можете їх точно налаштувати та окреслити окремо

13

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

Дві основні з них - поліморфізм та валідація. Навіть якщо це просто дурна структура даних.

Скажімо, у нас такий простий клас:

public class Bottle {
  public int amountOfWaterMl;
  public int capacityMl;
}

Дуже простий клас, який вміщує, скільки в ньому рідини, і яка її ємність (у мілілітрах).

Що відбувається, коли я роблю:

Bottle bot = new Bottle();
bot.amountOfWaterMl = 1500;
bot.capacityMl = 1000;

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

Але є й інша проблема. Що робити, якщо пляшки були лише одного типу контейнера? Що робити, якщо у нас було декілька контейнерів, все з ємностями та кількістю рідини? Якби ми могли просто зробити інтерфейс, ми могли б дозволити решті нашої програми прийняти цей інтерфейс, і пляшки, джерікани та всілякі речі просто працювали б між собою. Хіба це не було б краще? Оскільки інтерфейси вимагають методів, це теж непогана річ.

Ми закінчили б щось на кшталт:

public interface LiquidContainer {
  public int getAmountMl();
  public void setAmountMl(int amountMl);
  public int getCapacityMl();
}

Чудово! А тепер ми просто змінюємо Пляшку на це:

public class Bottle extends LiquidContainer {
  private int capacityMl;
  private int amountFilledMl;

  public Bottle(int capacityMl, int amountFilledMl) {
    this.capacityMl = capacityMl;
    this.amountFilledMl = amountFilledMl;
    checkNotOverFlow();
  }

  public int getAmountMl() {
    return amountFilledMl;
  }

  public void setAmountMl(int amountMl) {
     this.amountFilled = amountMl;
     checkNotOverFlow();
  }
  public int getCapacityMl() {
    return capacityMl;
  }

  private void checkNotOverFlow() {
    if(amountOfWaterMl > capacityMl) {
      throw new BottleOverflowException();
    }
}

Я залишу визначення BottleOverflowException як вправу для читача.

Тепер зауважте, наскільки це надійніше. Зараз ми можемо мати справу з будь-яким типом контейнера в нашому коді, приймаючи LiquidContainer замість пляшки. І як ці пляшки поводяться з подібними матеріалами, все може відрізнятися. Ви можете мати пляшки, які записують їх стан на диск, коли він змінюється, або пляшки, які зберігають у базах даних SQL, або GNU знає, що ще.

І все це може мати різні способи поводження з різними дурнями. Пляшка просто перевіряє, і якщо вона переповнена, вона кидає RuntimeException. Але це може бути неправильним. (Існує корисна дискусія про обробку помилок, але я спеціально тримаю це дуже просто. Люди в коментарях, ймовірно, вкажуть на недоліки цього спрощеного підходу.;))

І так, схоже, ми переходимо від дуже простої ідеї до швидкого отримання набагато кращих відповідей.

Зауважте також, що ви не можете змінити ємність пляшки. Тепер він встановлений в камені. Ви можете зробити це за допомогою int, оголосивши його остаточним. Але якби це був список, ви могли б випорожнити його, додати до нього нові речі тощо. Ви не можете обмежити доступ до торкання нутрощів.

Є ще третє, що не всі звернулися до уваги: ​​геттери та сетери використовують виклики методів. Це означає, що вони виглядають як звичайні методи скрізь. Замість того, щоб мати дивний специфічний синтаксис для DTO та інших матеріалів, ви маєте всюди те саме.


2
Дякую за перше напівпристойне пояснення інтерфейсів, які я прочитав, не містить посилань на "пульти" або "автомобілі"
djvs

1
"Ви можете мати пляшки, які записують їх стан на диску, коли він змінюється, або пляшки, які зберігають на базах даних SQL", я зависла так жорстко xD. Але в будь-якому випадку, приємна ідея її представити!
Ксерус

10

На мовах, які не підтримують "властивості" (C ++, Java) або потребують перекомпіляції клієнтів при зміні полів у властивості (C #), використання методів get / set простіше змінити. Наприклад, додавання логіки перевірки до методу setFoo не вимагатиме зміни публічного інтерфейсу класу.

У мовах, які підтримують "реальні" властивості (Python, Ruby, можливо Smalltalk?), Немає сенсу отримувати / встановлювати методи.


1
Re: C #. Якщо ви додасте функціональність до get / set, чи все-таки це не вимагатиме перекомпіляції?
пароплав25

@ steamer25: вибачте, неправильно введено. Я мав на увазі, що клієнтам класу доведеться перекомпілювати.
Джон Міллікін

5
Додавання логіки перевірки до методу setFoo не потребуватиме зміни інтерфейсу класу на мовному рівні , але це змінює фактичний інтерфейс , який називається контрактом, оскільки він змінює передумови. Чому б хотілося, щоб компілятор не сприймав це як переломну зміну, коли воно є ?
Р. Мартіньо Фернандес

@ R.MartinhoFernandes, як можна вирішити цю "зламану" проблему? Компілятор не може визначити, зламаний він чи ні. Це викликає занепокоєння, коли ви пишете бібліотеки для інших, але ви робите це як універсальний zOMG, будьте драконами!
Філ

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

6

Один з основних принципів дизайну ОО: інкапсуляція!

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


23
Пробірки інкапсуляції та сетери пропонують смішно тонкі. Дивіться тут .
sbi

Якщо у вашому загальнодоступному інтерфейсі зазначено, що "foo" має тип "T" і його можна встановити будь-що, ви ніколи цього не можете змінити. Ви не можете остаточно вирішити, щоб він був тип "Y", а також не можете накладати такі правила, як обмеження розміру. Таким чином, якщо у вас є публічний get / set, який нічого не робить / встановлює, ви не отримуєте нічого, що публічне поле не запропонує, і робить його більш громіздким у використанні. Якщо у вас є обмеження, наприклад, об'єкт може бути встановлений на нульове значення або значення повинно бути в межах діапазону, тоді так, потрібен буде метод публічного набору, але ви все одно представляєте контракт на встановлення цього значення, яке може " t зміна
thecoshman

Чому контракт не може змінитися?
Філ

5
Чому все слід продовжувати складати, якщо контракти змінюються?
Р. Мартіньо Фернандес

5

Ви повинні використовувати геттери та сетери, коли:

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

Тож це дуже рідко є загальним питанням ОО; це специфічне для мови питання з різними відповідями для різних мов (та різних випадків використання).


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

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

* Навіть для цього простого класу вам не обов’язково потрібно дозволити встановлення значень xта yзначень. Якщо це дійсно клас, вона не повинна мати такі методи , як translate, rotateі т.д.? Якщо це лише клас, оскільки у вашій мові немає записів / структур / названих кортежів, то це насправді не питання про ОО…


Але ніхто ніколи не займається загальним дизайном OO. Вони роблять дизайн та реалізацію певною мовою. А в деяких мовах геттери та сетери далеко не марні.

Якщо ваша мова не має властивостей, то єдиний спосіб представити те, що концептуально є атрибутом, але насправді обчислюється, або перевіряється тощо, - це getters та setters.

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

Що стосується "що, якщо я хочу змінити свою реалізацію пізніше?" питання (яке повторюється кілька разів у різній редакції як у питанні ОП, так і у прийнятій відповіді): Якщо це дійсно чиста зміна реалізації, і ви почали з атрибуту, ви можете змінити його на властивість, не впливаючи на інтерфейс. Якщо, звичайно, ваша мова цього не підтримує. Так що це справді знову той самий випадок.

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

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


4

З точки зору проектування орієнтації на об'єкт, обидві альтернативи можуть завдати шкоди підтримці коду, послаблюючи інкапсуляцію класів. Для обговорення ви можете переглянути цю чудову статтю: http://typicalprogrammer.com/?p=23


3

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

Є деякі переваги у використанні методів getter та setter, наприклад, можливість дозволяти створювати членів із складною функціональністю, до якої ви можете отримати доступ до подібних властивостей. Вони також дозволяють створювати властивості лише для читання та запису.

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

Коли ви пишете заняття, вам завжди пропонується зробити якомога більше змінних ваших примірників приватними та відповідно додати методи getter та setter. Це тому, що є кілька разів, коли ви, можливо, не бажаєте дозволяти користувачам змінювати певні змінні у ваших класах. Наприклад, якщо у вас є приватний статичний метод, який відстежує кількість екземплярів, створених для певного класу, ви не хочете, щоб користувач міняв цей лічильник за допомогою коду. Тільки оператор конструктора повинен збільшувати цю змінну, коли вона викликається. У цій ситуації ви можете створити приватну змінну екземпляра та дозволити метод getter лише для змінної лічильника, що означає, що користувачі можуть отримати поточне значення лише за допомогою методу getter, і вони не зможуть встановити нові значення використовуючи метод сетера.


3

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

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

int getVar() const { return var ; }

Отже, у вас є:

doSomething( obj->getVar() ) ;

Замість

doSomething( obj->var ) ;

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

Тому я програмую так (припускаючи "спритний" тип підходу, тобто коли я пишу код, не знаючи точно що саме буде робити / не маю часу чи досвіду для планування складного інтерфейсу стилю водоспаду):

1) Почніть з усіх публічних членів основних об'єктів з даними та поведінкою. Ось чому у всьому моєму C ++ «прикладі» коду ви помітите мене, використовуючи structзамість classусіх місць.

2) Коли внутрішня поведінка об'єкта для члена даних стає досить складною (наприклад, він любить зберігати внутрішній std::listу якомусь порядку), записуються функції типу аксесуара. Оскільки я програмую сам, я не завжди встановлюю члена privateодразу, але десь внизу еволюції класу член буде "підвищений" або до, protectedабоprivate .

3) Класи, які мають повністю чітку форму та мають суворі правила щодо їх внутрішніх справ (тобто вони точно знають, що роблять, а ви не повинні "ебать" (технічний термін) з її внутрішніми classособами ), отримують позначення, приватні члени за замовчуванням, і дозволено бути лише декількома членами public.

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


1
"... чітко визначений інтерфейс, який ви не можете просто накрутити з внутрішніми елементами" та перевірки в сеттерах.
Agi Hammerthief

3

Є вагомий привід розглянути можливість використання аксесуарів, якщо немає спадщини власності. Дивіться наступний приклад:

public class TestPropertyOverride {
    public static class A {
        public int i = 0;

        public void add() {
            i++;
        }

        public int getI() {
            return i;
        }
    }

    public static class B extends A {
        public int i = 2;

        @Override
        public void add() {
            i = i + 2;
        }

        @Override
        public int getI() {
            return i;
        }
    }

    public static void main(String[] args) {
        A a = new B();
        System.out.println(a.i);
        a.add();
        System.out.println(a.i);
        System.out.println(a.getI());
    }
}

Вихід:

0
0
4

3

Геттери та сетери використовуються для реалізації двох основних аспектів об'єктно-орієнтованого програмування:

  1. Абстракція
  2. Інкапсуляція

Припустимо, у нас є клас працівника:

package com.highmark.productConfig.types;

public class Employee {

    private String firstName;
    private String middleName;
    private String lastName;

    public String getFirstName() {
      return firstName;
    }
    public void setFirstName(String firstName) {
       this.firstName = firstName;
    }
    public String getMiddleName() {
        return middleName;
    }
    public void setMiddleName(String middleName) {
         this.middleName = middleName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getFullName(){
        return this.getFirstName() + this.getMiddleName() +  this.getLastName();
    }
 }

Тут деталі реалізації Повного Імені приховані від користувача та не доступні безпосередньо користувачеві, на відміну від публічного атрибута.


1
Мені багато тонн геттерів і сетер, які не роблять нічого унікального, марні. getFullName - виняток, оскільки він робить щось інше. Маючи лише три змінні загальнодоступні, то зберігання getFullName полегшить читання програми, але при цьому приховатиме те, що має повне ім'я. Як правило, я цілком в порядку з геттерами та сетерами, якщо. вони роблять щось унікальне та / або b. у вас є тільки один, так, ви могли б провести публічний фінал і все, окрім цього
FacelessTiger

1
Користь при цьому полягає в тому, що ви можете змінювати внутрішні класи класу, не змінюючи інтерфейс. Скажіть, замість трьох властивостей у вас був один - масив рядків. Якщо ви використовували геттери та сеттери, ви можете внести цю зміну, а потім оновити геттер / сеттер, щоб знати, що імена [0] - це ім'я, імена [1] - середина тощо. Але якщо ви просто використовували загальнодоступні властивості , вам також доведеться змінювати кожного співробітника, до якого зверталися, оскільки власності firstName, якими вони користуються, вже не існують.
Ендрю Хоус

1
@AndrewHows з того, що я бачив у реальному житті, коли люди змінюють внутрішні класи класу, вони також змінюють інтерфейс і роблять велику рефакторинг всього коду
Eildosa

2

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


Я ніколи не очікував, що геттер або сетер буде дорогою операцією. У таких випадках краще скористатися фабрикою: користуйтеся всіма необхідними сеттерами, а потім використовуйте дорогий executeабо buildметод.
Hubert Grzeskowiak

2

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

З іншого боку, якщо учасник є загальнодоступним, інструменти не дозволяють фільтрувати доступ для читання / запису до члена. Таким чином, ви повинні намагатися, хоча всі користувачі члена.


Ви можете зробити
клацання правою кнопкою миші

2

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


1

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


2
Я гадаю, що зміна поведінки геттера чи сетера - це не суттєва зміна. </sarcasm>
Р. Мартіньо Фернандес

@ R.MartinhoFernandes не завжди має бути таким. TBYS
Філ

1

Я просто хотів би накинути ідею анотації: @getter та @setter. За допомогою @getter ви повинні мати можливість obj = class.field, але не class.field = obj. З @setter, навпаки. За допомогою @getter та @setter ви маєте змогу зробити і те, і інше. Це дозволило б зберегти інкапсуляцію та скоротити час, не викликаючи тривіальних методів під час виконання.


1
Він буде реалізовуватися під час виконання за допомогою "тривіальних методів". Насправді, напевно, нетривіально.
Філ

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