Зачем использовать геттеры и сеттеры / аксессоры?

В чем преимущество использования геттеров и сеттеров, которые только получают и устанавливают, вместо простого использования общедоступных полей для этих переменных?

Если геттеры и сеттеры когда-либо делают больше, чем просто получение / установка, я могу понять это очень быстро, но я не на 100% понимаю, как:

public String foo;

хуже чем:

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

В то время как первый требует намного меньше шаблонного кода.


person Dean J    schedule 14.10.2009    source источник
comment
@Dean J: Дублируйте со многими другими вопросами: stackoverflow.com/search?q=getters+setters   -  person Asaph    schedule 14.10.2009
comment
Конечно, и то, и другое одинаково плохо, когда объект не нуждается в изменении свойства. Я бы предпочел сделать все приватным, а затем добавить геттеры, если это полезно, и сеттеры, если необходимо.   -  person Tordek    schedule 14.10.2009
comment
Аксессоры Google - это зло   -  person OMG Ponies    schedule 14.10.2009
comment
Аксессоры - зло, если вы пишете функциональный код или неизменяемые объекты. Если вы пишете изменяемые объекты с сохранением состояния, они очень важны.   -  person Christian Hayter    schedule 14.10.2009
comment
Скажи, а не спрашивай. pragprog.com/articles/tell-dont-ask   -  person Dave Jarvis    schedule 15.10.2009
comment
За исключением 6 и 8, я бы осмелился сказать, что ни один из этих пунктов не применяется в 99% случаев. Тем не менее, я бы хотел, чтобы java использовала String s = employee.name() и employee.name("oscar") вместо getName () setName ()   -  person OscarRyz    schedule 28.10.2009
comment
@Oscar Reyes, да, я согласен с тем, что 6 и 8 - самые распространенные два из моего опыта. Тем не менее, я по-прежнему предпочитаю не использовать синтаксис C # ish; мой старик мозг запутался.   -  person Dean J    schedule 29.10.2009
comment
Что ж, я удивлен, что никто не говорит о синхронизации данных. Предположим, вы используете public String foo; его небезопасный поток! Вместо этого вы можете определить getter setters с методами синхронизации, чтобы избежать неверности данных [я имею в виду, что другой поток испортил foo]. Я чувствовал, что об этом стоит упомянуть.   -  person Prasanth    schedule 23.08.2012
comment
@goldenparrot: Чаще, чем никогда, синхронизация одиночных обращений к объекту является неэффективной или даже склонной к проблемам синхронизации (когда вам нужно изменить несколько свойств объекта одновременно). IME, вам часто нужно обернуть операции в целом, которые осуществляют множественный доступ к объекту. Этого можно добиться только путем синхронизации на стороне пользователей типа.   -  person sbi    schedule 24.08.2012
comment
Не объединяйте ваши любимые части всех ответов в сам вопрос. Это сайт вопросов и ответов, а не форум.   -  person Keith Pinson    schedule 25.03.2013
comment
@ErikReppen, что я должен прочитать, чтобы понять ООП в первую очередь?   -  person Timo Huovinen    schedule 10.08.2013
comment
Существует также очень важная проблема совместного использования кода с другими людьми: если вы рассматриваете поля объекта как части внешнего интерфейса для использования другими людьми, то изменение поля на функцию может быть невозможно без нарушения изменений в коде других людей.   -  person Timo Huovinen    schedule 10.08.2013
comment
@ErikReppen Спасибо за ссылку, я работаю над пониманием того, что должно быть ООП, но это оказывается трудным из-за количества распространяющейся дезинформации. P.S. Я также считаю, что Википедия - один из лучших источников во многих областях науки.   -  person Timo Huovinen    schedule 13.08.2013
comment
@TimoHuovinen - все дело в том, чтобы не выяснять, какая из 500 функций на самом деле изменяет значение. Вы делаете ценность или набор ценностей чем-то ответственным, а не чем-то, что нужно помещать на "американские горки" парам / возвратов. Избегайте обычных геттеров / сеттеров и общедоступных свойств, и вам часто придется остановиться и подумать о том, как смоделировать свое приложение таким образом, чтобы его было легче читать, изменять, повторно использовать большие части, отлаживать и иметь уверенность. в без проверки bejeezus из него. Java и C # превзошли ООП, а затем отказались от него, ИМО.   -  person Erik Reppen    schedule 14.08.2013
comment
Еще одна статья, предлагающая рекомендации о том, где и когда использовать геттеры и сеттеры: Общедоступные или частные переменные-члены? Принцип YAGNI предписывает нам не добавлять конструкции, пока мы действительно не узнаем, что они нам понадобятся.   -  person AgilePro    schedule 28.10.2014
comment
Пункты 2, 3 (?), 4, 5 и 8: предварительно да. Остальные, однозначно нет. Почему имеет значение, использовали ли вы Python, C #, Ruby, Objective-C или esolang, если ваш код простой, элегантный и легко обслуживаемый / расширяемый?   -  person Agi Hammerthief    schedule 19.12.2014
comment
666 голосов за не кажутся совпадением   -  person sitilge    schedule 09.09.2015
comment
Люди могут легко сказать, что вы не использовали Python. на самом деле должно быть Nr. 1!   -  person Kaiserludi    schedule 30.10.2015
comment
@Kaiserludi Не могли бы вы проиллюстрировать, как это хорошо?   -  person Joschua    schedule 04.08.2016
comment
@DeanJ Не могли бы вы объяснить номер 10?   -  person Joschua    schedule 04.08.2016
comment
@Joshua: Я просто шутил, потому что автор явно несерьезно добавлял его в список.   -  person Kaiserludi    schedule 04.08.2016
comment
11. Это полезные места для установки точек останова при отладке состояния, полученного / измененного из различных мест.   -  person Steve Hollasch    schedule 20.09.2016
comment
Недавний вопрос напомнил мне еще об одной причине для set-методов: возможность запускать изменение свойства.   -  person VGR    schedule 15.03.2017


Ответы (41)


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

Вот некоторые из известных мне причин:

  • Инкапсуляция поведения, связанного с получением или установкой свойства - это позволяет позже добавить дополнительные функции (например, проверку).
  • Скрытие внутреннего представления свойства при раскрытии свойства с использованием альтернативного представления.
  • Изоляция общедоступного интерфейса от изменений - позволяя общедоступному интерфейсу оставаться постоянным, пока реализация изменяется, не затрагивая существующих потребителей.
  • Управление семантикой срока службы и управления (удаления) памяти свойства - особенно важно в средах с неуправляемой памятью (например, C ++ или Objective-C).
  • Предоставление точки перехвата отладки, когда свойство изменяется во время выполнения - отладка, когда и где свойство изменилось на определенное значение, может быть довольно сложной без этого на некоторых языках.
  • На ум приходят улучшенные возможности взаимодействия с библиотеками, которые предназначены для работы с геттерами / установщиками свойств - Mocking, Serialization и WPF.
  • Разрешение наследникам изменять семантику поведения и отображения свойства путем переопределения методов получения / установки.
  • Разрешение передачи геттера / сеттера в виде лямбда-выражений, а не значений.
  • Геттеры и сеттеры могут разрешать разные уровни доступа - например, get может быть общедоступным, но набор может быть защищен.
person LBushkin    schedule 14.10.2009

Поскольку через 2 недели (месяцы, годы), когда вы поймете, что вашему сеттеру нужно сделать больше, чем просто установить значение, вы также поймете, что свойство использовалось непосредственно в 238 других классах: -)

person ChssPly76    schedule 14.10.2009
comment
Я сижу и смотрю на приложение на 500 тысяч строк, в котором никогда не было необходимости. Тем не менее, если это понадобится однажды, это вызовет кошмар обслуживания. Достаточно хорошо для меня. - person Dean J; 14.10.2009
comment
Я могу только позавидовать вам и вашему приложению :-) Тем не менее, это также действительно зависит от вашего программного стека. Например, Delphi (и C # - я думаю?) Позволяет вам определять свойства как граждан 1-го класса, где они могут читать / записывать поле напрямую, но - если вам это нужно - делать это также с помощью методов getter / setter. Мучо удобно. Увы, в Java нет - не говоря уже о стандарте javabeans, который заставляет вас также использовать геттеры / сеттеры. - person ChssPly76; 14.10.2009
comment
Проверка - классический пример выполнения чего-то особенного в установщике, особенно если вы не полностью доверяете потребителям своего кода ... - person Rowland Shaw; 14.10.2009
comment
Хотя это действительно хорошая причина для использования средств доступа, многие среды программирования и редакторы теперь предлагают поддержку рефакторинга (либо в среде IDE, либо в виде бесплатных надстроек), что несколько снижает влияние проблемы. - person LBushkin; 14.10.2009
comment
@LBushkin - при условии, что ваш код не будет использоваться публично. - person UpTheCreek; 14.10.2009
comment
звучит как доработанная оптимизация - person cmcginty; 16.06.2012
comment
Вопрос, который вам нужно задать, когда вы задаетесь вопросом, следует ли реализовать геттеры и сеттеры: Зачем пользователям класса вообще нужен доступ к внутренностям класса? На самом деле не имеет значения, делают ли они это. напрямую или экранированный тонким псевдо-слоем - если пользователям нужен доступ к деталям реализации, то это признак того, что класс не предлагает достаточной абстракции. См. Также этот комментарий. - person sbi; 24.08.2012
comment
Эта проблема не является индикатором того, что вам нужно использовать методы set или get. Это показатель того, что всей команде нужно избавиться от IDE и научить писать, понимать и поддерживать ООП без них. - person Erik Reppen; 13.06.2013
comment
@ErikReppen Как я уже говорил выше, это зависит от конкретной языковой реализации. Для тех, где свойства не являются первоклассными гражданами (например, Java), совершенно неважно, используете ли вы какую-то среду IDE или простой vi для написания кода - как только свойство было открыто открыто, вы не можете вернуть его. - person ChssPly76; 13.06.2013
comment
@ ChssPly76 IMO, вы действительно не должны показывать свойства прямо или косвенно в первую очередь (в большинстве случаев - всегда исключения из правил). Они несут ответственность за этот объект. Когда вы проектируете с точки зрения данных, которые меняются только как побочный эффект, когда объекты говорят друг другу делать что-то, кроме того, какие данные нужно установить, вам нужно останавливаться и время от времени думать, но это приводит к гораздо более удобной в обслуживании / модульной архитектуре IMO. Это то, что позволяет поддерживать сложность в динамическом языке. - person Erik Reppen; 13.06.2013
comment
@ ChssPly76 Я не объяснил смысл удаления IDE. Попробуйте написать код без него, когда вы фактически получили глобальный доступ к одной и той же переменной из 238 мест и теперь должны выяснить, где что-то пошло не так. - person Erik Reppen; 12.08.2013
comment
К чему все разговоры об удалении IDE? Зачем кому-то это делать? Конечно, я знаю, как использовать ed, и временами это инструмент для работы. Однако написание программного обеспечения - не тот случай. - person Phil; 30.10.2013
comment
@sbi Я не понимаю почему? Я имею в виду, что если у вас есть очень простой случай класса людей, поле будет first_name, и, очевидно, вы хотите просто получить это поле дословно в какой-то момент. И вам следует использовать геттер. Возможно, в будущем вы полностью измените реализацию своего класса, чтобы класс асинхронно извлекал это с сервера или делал что-то еще. - person Zorf; 14.10.2014
comment
@Zorf: Если все ваши person хранят имя и фамилию, то это не что иное, как (прославленный) struct и, следовательно, не ООП, а структурированное программирование. (Получат ли сеттеры и геттеры что-нибудь в этом сценарии из-за простого доступа к данным, в лучшем случае сомнительно: A) Как еще, как не в строке, вы бы представляли имена людей? И я говорю здесь о практических сценариях, а не о теории, потому что B) за 20 лет практики я ни разу не сталкивался с такой ситуацией.) - person sbi; 14.10.2014

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

Часто упоминаемое преимущество пар геттер / сеттер - нет. Утверждается, что вы можете изменить реализацию, и ваших клиентов не нужно перекомпилировать. Предположительно, сеттеры позволяют позже добавлять такие функции, как проверка, и вашим клиентам даже не нужно об этом знать. Однако добавление проверки к сеттеру - это изменение его предварительных условий, нарушение предыдущего контракта, которое было попросту: «вы можете вставить сюда что угодно, и вы можете получить то же самое позже. от получателя ".

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

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

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

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

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

Добавление сквозных пар геттер / сеттер к такому классу не добавляет ценности. Другие классы должны предоставлять значимые операции, а не только операции, которые уже есть в полях. Вот как вы можете определять и поддерживать полезные инварианты.

Клиент: «Что я могу делать с объектом этого класса?»
Дизайнер: «Вы можете читать и записывать несколько переменных».
Клиент: «Ой ... круто, наверное?»

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

person R. Martinho Fernandes    schedule 24.08.2012
comment
Отличный ответ (+1). Моя единственная критика заключается в том, что мне потребовалось несколько чтений, чтобы понять, чем проверка в последнем абзаце отличается от проверки в первых нескольких (которую вы отбросили во втором случае, но продвинули в первом); изменение формулировки может помочь в этом отношении. - person Lightness Races in Orbit; 07.07.2013
comment
Это отличный ответ, но, увы, нынешняя эпоха забыла, что такое скрытие информации и для чего она нужна. Они никогда не читали о неизменности и в своем стремлении к максимальной гибкости никогда не рисовали диаграмму перехода между состояниями, которая определяла бы, какие юридические состояния объекта были и, следовательно, какие нет. - person Darrell Teague; 06.11.2013
comment
Ключевое наблюдение заключается в том, что геттеры гораздо полезнее, чем сеттеры. Геттер может возвращать вычисленное значение или кэшированное вычисленное значение. Все, что может сделать установщик, - это некоторая проверка, а затем изменение поля private. Если у класса нет сеттеров, его легко сделать неизменяемым. - person Raedwald; 12.12.2014
comment
Я согласен с большинством пунктов, особенно с YAGNI. НО: я использовал программу, которая создавала структуру объекта из нетривиального другого объекта. Произошла ошибка, один участник был обновлен неправильно. Я поискал вхождений: 380 вхождений. Из этих 380 вхождений только 40 устанавливали значение, остальные извлекали его. И только 1 сеттер вызвал ошибку. Если бы этот парень использовал сеттеры, я бы сэкономил много времени, потому что мне не пришлось бы смотреть на 340 строк кода, если бы он только извлекал значение. - person Toskan; 04.08.2015
comment
@Toskan - это просто пример случая, когда в вашем классе есть инварианты, а дизайнер забыл о них. Это не пример против моего случая, это «за». - person R. Martinho Fernandes; 04.08.2015
comment
@ R.MartinhoFernandes ehrm, вы можете указать, о чем вы имеете в виду? Поскольку нет, это нетривиальная структура, инварианты не являются решением. - person Toskan; 05.08.2015
comment
Эээ, я думаю, вы не знаете, что такое инвариант класса. Если это нетривиальная структура, это в значительной степени означает, что у нее есть инварианты, которые необходимо поддерживать, и ее просто невозможно спроектировать без их учета. Произошла ошибка, один участник был обновлен неправильно. также в значительной степени читается как обновление члена нарушило инварианты класса. Хорошо спроектированный класс не позволяет клиентскому коду нарушать его инварианты. - person R. Martinho Fernandes; 05.08.2015
comment
@PreferenceBean Итак, что означает проверка в последнем абзаце? Я запутался, как и вы. - person user1914692; 09.02.2016
comment
Мне нравится аргумент. Да, договор означает, что пользователь не ожидал никаких изменений. - person user1914692; 09.02.2016
comment
@user, проверка означает одно и то же в обоих местах. Разница (как объясняется в последнем абзаце) в том, что аксессоры оправданы, если вы реализуете валидацию с самого начала, а не только на тот случай, если я захочу добавить валидацию позже. - person alexis; 08.06.2016
comment
+1 за «тупые держатели данных должны выглядеть как тупые держатели данных». К сожалению, в наши дни все, кажется, проектируют все вокруг тупых держателей данных, и многие фреймворки даже требуют этого ... - person Joeri Hendrickx; 29.08.2016
comment
...this claim that you can change the implementation and your clients don't have to be recompiled. ложно только в том случае, если вы измените договор. Вы можете изменить все внутренние компоненты типа, не изменяя его контракт, и именно такая возможность является причиной того, почему инкапсуляция - это вещь. Вы правы, утверждая, что изменение контракта без просмотра кода, который зависит от него, является злом, но не потому, что аксессоры / свойства существуют в любом случае - это скорее неправильное использование соглашения, которое почти всегда является лучшей практикой, если только тип не гарантированно имеет те же внутренности / реализация. - person Şafak Gür; 21.03.2018
comment
+1 за отличный ответ, но есть одно и, как ни странно, только одно преимущество геттеров и сеттеров в тупых держателях данных: большинство IDE скомпилированных языков имеют встроенную опцию для поиска всех ссылок на метод или свойство. Возможность найти все места, где данные устанавливаются с отфильтрованным геттером, за эти годы сэкономила мне огромное количество времени, и мне трудно представить отладку сложного кода без этого. - person Yuval Perelman; 24.12.2018
comment
@Toskan, имеющий сеттер / получатель, не полностью решает проблему, как я узнаю, что написал для него проблему, у меня был проект, в котором использовались геттеры / сеттеры, но сам объект не использовал свой сеттер при изменении своего собственного состояния, что это было часто. Поэтому всякий раз, когда я хотел узнать, изменилось ли поле, мне приходилось смотреть на все случаи использования его установщика, а также на все случаи, когда объект записывал в свое собственное внутреннее поле. Вы можете сказать, что можете исправить это, если сам объект всегда будет использовать свой собственный сеттер, но это может вызвать бесконечные рекурсии и ненужные срабатывания событий. - person jrh; 17.08.2020
comment
... или, другими словами, get / setters могут иногда добавлять контекст того, кто хочет знать / кто это установил, что, на мой взгляд, обычно является более сложным, чем оно того стоит. Обычно приводит к зависанию пользовательских интерфейсов, которые слишком часто перерисовываются, и к неэффективным сетевым соединениям, которые отправляют 100 МБ данных по 32 бита за раз. Я сильно упрощаю здесь, но я никогда не обнаруживал, что говорю: ну, если бы только этот объект мог обновлять другие вещи, и я довольно часто говорил, что мне нужно сделать этот хак, чтобы предотвратить массовое обновление, вызывающее 1000 событий. - person jrh; 17.08.2020
comment
@jrh моя IDE в настоящее время может обнаруживать и различать чтение / запись в поле. 5 лет назад этого не было - person Toskan; 17.08.2020
comment
@Toskan что это за IDE? - person jrh; 17.08.2020
comment
@jrh Я не использовал java в течение многих лет, но для некоторых языков, таких как javascript и php intellij (с phpstorm и webstorm, интегрированными afaik), помогает. - person Toskan; 18.08.2020
comment
@Toskan - это довольно интересная функция, я никогда не видел ее ни в одной из IDE, которые я использовал (кроме VS с C ++, и когда я попробовал ее, ее реализация была глубоко ошибочной и неточной). Надеюсь, это будет реализовано в большем количестве редакторов. - person jrh; 18.08.2020

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

Допустим, вы просматриваете сотни строк кода и наталкиваетесь на следующее:

person.name = "Joe";

Это красиво простой фрагмент кода, пока вы не поймете, что это сеттер. Теперь вы следите за этим установщиком и обнаруживаете, что он также устанавливает person.firstName, person.lastName, person.isHuman, person.hasReallyCommonFirstName и вызывает person.update (), который отправляет запрос в базу данных и т. Д. где произошла ваша утечка памяти.

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

person Kai    schedule 14.10.2009
comment
да. В настоящее время проводится рефакторинг большой базы кода, и это было кошмаром. Геттеры и сеттеры делают слишком много, включая вызов других очень загруженных геттеров и сеттеров, которые в конечном итоге сводят читабельность к нулю. Валидация - отличный повод для использования средств доступа, но использование их для большего, чем это, кажется, исключает любую потенциальную выгоду. - person Fadecomic; 14.05.2012
comment
Это аргумент против синтаксического сахара, а не против сеттеров в целом. - person Phil; 29.10.2013
comment
Верно и верно, но, более того, он указывает, почему отдельные установщики свойств открывают дверь для недопустимых состояний, не имея абсолютно никаких средств для обеспечения целостности любого заданного объекта, который позволяет абстракции просочиться. - person Darrell Teague; 06.11.2013
comment
Это красиво простой фрагмент кода, пока вы не поймете, что это сеттер - эй, это был исходный пост о Java или о C #? :) - person Honza Zidek; 13.04.2017
comment
По поводу удобочитаемости полностью согласен. Совершенно очевидно, что происходит при вызове person.name = "Joe";. В информации нет беспорядка, выделение синтаксиса показывает, что это поле, а рефакторинг проще (нет необходимости реорганизовывать два метода и поле). Во-вторых, можно забыть все эти потраченные впустую мозговые циклы, когда мы думаем, что getIsValid () или, должно быть, isValid () и т. Д., Можно забыть. Я не могу вспомнить ни одного случая, когда меня спасли от ошибки геттер / сеттер. - person Will; 18.10.2017
comment
что это больше проблема с очисткой кода, чем с геттерами и сеттерами, я думаю - person Armando SM; 18.05.2020
comment
@Phil Вы писали: это аргумент против синтаксического сахара, а не против сеттеров в целом. Подождите минуту. Если сеттеры - это синтаксический сахар, как вы подразумеваете, то, будучи аргументом против синтаксического сахара, они также являются аргументом против сеттеров. - person OCDev; 09.07.2020
comment
@OCDev совсем наоборот. Когда геттеры и сеттеры замаскированы под доступ к свойствам (синтаксический шугаринг), они скрывают тот факт, что может происходить нечто большее, чем простое присваивание. Могут быть аргументы против того, чтобы геттеры и сеттеры делали больше, чем описано на банке, но если они действительно делают больше, чем описано на банке, лучше не засахаривать, потому что это еще больше маскирует то, что продолжается. - person Phil; 10.07.2020
comment
У меня проблемы с отладкой такого простого свойства, как просмотр его значения. Кроме того, свойства - это инструмент, который дает пользователям возможность втиснуть невероятные объемы кода в ... кажущуюся невинной переменной. И я сторонник свободы в языке. - person mireazma; 08.10.2020

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

Вы можете найти больше о них в разделе 3.5 Elegant Objects (моей книги об объектно-ориентированных программирование).

person yegor256    schedule 23.09.2014
comment
Геттеры и сеттеры предлагают анемичную модель предметной области. - person Raedwald; 12.12.2014
comment
Интересная точка зрения. Но в большинстве случаев программирования нам нужны структуры данных. Возьмем пример собаки из связанной статьи. Да, вы не можете изменить вес реальной собаки, установив атрибут ... но new Dog() - это не собака. Это объект, содержащий информацию о собаке. И для этого использования естественно иметь возможность исправить неправильно записанный вес. - person Stephen C; 01.07.2016
comment
Что ж, я сказал вам, что большинству полезных программ не нужно моделировать / моделировать объекты реального мира. ИМО, это вообще не о языках программирования. Это то, для чего мы пишем программы. - person Stephen C; 02.07.2016
comment
Реальный мир или нет, Егор совершенно прав. Если у вас действительно есть структура и вам не нужно писать какой-либо код, который ссылается на нее по имени, поместите ее в хеш-таблицу или другую структуру данных. Если вам действительно нужно написать для него код, тогда поместите его как член класса и поместите код, который управляет этой переменной, в тот же класс и опустите установщик и получатель. PS. Хотя я в основном разделяю точку зрения Егора, я пришел к выводу, что аннотированные bean-компоненты без кода являются в некоторой степени полезными структурами данных - также иногда необходимы геттеры, а сеттеры никогда не должны существовать. - person Bill K; 01.05.2017
comment
Я увлекся - весь этот ответ, хотя и правильный и актуальный, напрямую не касается вопроса. Возможно, следует сказать, что оба сеттера / получателя И общедоступные переменные неверны ... Чтобы быть абсолютно конкретным, сеттеры и доступные для записи общедоступные переменные никогда не должны использоваться, тогда как геттеры в значительной степени идентичны общедоступным конечным переменным и иногда являются необходимым злом, но ни то, ни другое намного лучше, чем другие. - person Bill K; 01.05.2017
comment
Возможно, названия методов иногда отражают более глубокое понимание разработчика, а может быть, дело обстоит наоборот ... элементы языка влияют на привычки разработчиков. Но синтаксис языка и символы изобилуют элементами, которые эволюционировали с течением времени и больше не являются (если вообще когда-либо) точной метафорой того, что они должны представлять. Хотя вы делаете несколько хороших замечаний, мне кажется, что я утверждаю, что Java - это глупое название языка программирования, потому что мы не можем пить его, сидя в кафе. Это нормально - переопределить набор, придав ему более полное значение, не отменяя его. - person C Perkins; 14.05.2017
comment
Я никогда не понимал геттеров / сеттеров. С первого курса Java101, который я прошел в колледже, казалось, что они поощряют строительство без абстракций, и сбили меня с толку. Но есть такой случай: ваш объект может иметь очень много разных поведений. Тогда возможно, что вы не надеетесь реализовать их все. Вы создаете сеттеры / получатели и удобно сообщаете своим пользователям, что если вам нужно поведение, которое я пропустил, наследуйте и реализуйте их самостоятельно. В конце концов, я дал вам аксессуары. - person meguli; 05.06.2017
comment
В этом смысле «живых объектов» не должно быть set…() и get…(), а скорее remember…() и tell…(). Просто эти get и set короче для ввода. Кроме того, объект, описывающий другой объект - например, форма в бумажном переплете - должен включать это в имя класса, но это опять же длинно. Мы не можем изменить вес собаки, и мы не делаем этого, мы меняем только вес, указанный в форме приема собаки. - person Matthias Ronge; 14.05.2018

Есть много причин. Мне больше всего нравится, когда вам нужно изменить поведение или отрегулировать то, что вы можете установить для переменной. Например, допустим, у вас есть метод setSpeed ​​(int speed). Но вы хотите, чтобы вы могли установить максимальную скорость только 100. Сделайте что-то вроде:

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

А что, если ВЕЗДЕ в коде вы использовали общедоступное поле, а затем поняли, что вам нужно указанное выше требование? Получайте удовольствие от поиска каждого использования публичного поля вместо того, чтобы просто изменять свой сеттер.

Мои 2 цента :)

person Peter D    schedule 14.10.2009
comment
Отслеживать каждое использование публичного поля не должно быть так сложно. Сделайте его закрытым и позвольте компилятору найти их. - person Nathan Fellman; 14.10.2009
comment
это, конечно, правда, но зачем делать это сложнее, чем было задумано. Подход get / set по-прежнему является лучшим ответом. - person Hardryv; 14.10.2009
comment
Если другие проекты также не используют это общедоступное поле, то есть если вы делитесь своей библиотекой с внешними источниками - person PostMan; 15.10.2009
comment
Отслеживание вещей не должно быть проблемой в наши дни; Я использую IDE. Типы проектов, над которыми я работаю, никогда не передаются внешним источникам. - person Dean J; 15.10.2009
comment
@Nathan: Найти другие способы использования не проблема. Менять их все. - person Graeme Perrow; 08.11.2009
comment
@GraemePerrow Alt-Shift-R (eclipse - другие IDE могут сделать это по-другому). Бум, все изменилось). - person Phil; 29.10.2013
comment
@GraemePerrow необходимость их всех менять - это преимущество, а не проблема :( Что, если бы у вас был код, предполагающий, что скорость могла быть выше 100 (потому что, вы знаете, до того, как вы разорвали контракт, это могло быть!) (while(speed < 200) { do_something(); accelerate(); }) - person R. Martinho Fernandes; 30.10.2013
comment
@GraemePerrow, мы не живем в эпоху блокнотов ... и в будущем, вероятно, будут лучшие IDE, а не более паршивые. - person Pacerier; 07.08.2014
comment
@Nathan иногда у вас есть только интерпретатор (PHP), получайте удовольствие, находя их! :) - person Dennis; 06.11.2014
comment
Вы меняете договор между клиентом и классом. Клиенты могут подумать, что скорость не ограничена, и их поведение может нарушиться. Необходимость исправить все вхождения на самом деле является хорошим способом проверить использование интерфейса, чтобы убедиться, что новый контракт не нарушает клиентский код. - person Emiliano; 09.01.2015
comment
Я не знаю, не было ли в IDE версии 09 этих инструментов рефакторинга, но на сегодняшний день это действительно не проблема. Любая достойная среда IDE предоставляет метод поля инкапсуляции поля, в котором общедоступные поля могут быть легко преобразованы в методы получения / установки. Это также изменит все существующие вхождения кода для использования вновь созданных средств доступа. Так что придерживайтесь YAGNI и измените его через несколько секунд, если вам это нужно. - person Julian Sievers; 08.07.2015
comment
ОЧЕНЬ плохой пример! Кто-то должен позвонить: myCar.setSpeed(157); и через несколько строк speed = myCar.getSpeed(); А теперь ... желаю вам счастливой отладки, пытаясь понять, почему speed==100, когда должно быть 157 - person Piotr Aleksander Chmielowski; 23.02.2016
comment
Я не думаю, что добавлять логику в вашу модель - хорошая идея. Используйте валидатор или установите максимум из своих сервисов. - person amdev; 20.07.2017
comment
IMO Этот пример скрывает ошибки. Если у вас есть клиентский код, вызывающий ваш сеттер с неверными значениями, я думаю, вам нужно знать об этом, а не молча исправлять, что скрывает реальную проблему. - person Galik; 16.03.2018
comment
Разве упомянутое требование не должно быть настройкой экземпляра класса Speed, а не проверкой в ​​классе, который использует Speed? Таким образом, ограничение скорости будет тем, что класс скорости будет отслеживать и применять. Не классы, использующие скорость. - person imme; 03.05.2019

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

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

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

person Thomas Owens    schedule 14.10.2009

Зависит от вашего языка. Вы отметили это объектно-ориентированным, а не 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)
person jcdyer    schedule 14.10.2009
comment
Да, я уже сказал об этом в комментарии под моим ответом. Java - не единственный язык, использующий геттеры / сеттеры в качестве опоры, точно так же, как Python - не единственный язык, способный определять свойства. Однако главный момент остается неизменным - собственность - это не то же публичное поле. - person ChssPly76; 14.10.2009
comment
@ ChssPly76: но основная причина использования геттеров и сеттеров заключается в том, чтобы предотвратить необходимость изменения интерфейса, когда вы хотите добавить больше функций, а это означает, что вполне приемлемо - даже идиоматично - использовать общедоступные поля, пока такая функциональность не понадобится. - person jcdyer; 15.10.2009
comment
@jcd - совсем нет. Вы определяете свой интерфейс (публичный API был бы здесь более подходящим термином), открывая свои общедоступные поля. Как только это будет сделано, пути назад не будет. Свойства НЕ являются полями, потому что они предоставляют вам механизм для перехвата попыток доступа к полям (путем направления их к методам, если они определены); это, однако, не что иное, как синтаксический сахар над методами получения / установки. Это чрезвычайно удобно, но не меняет основную парадигму - раскрытие полей без контроля доступа к ним нарушает принцип инкапсуляции. - person ChssPly76; 16.10.2009
comment
@ ChssPly76 - я не согласен. У меня такой же контроль, как если бы они были свойствами, потому что я могу сделать их свойствами, когда мне нужно. Нет никакой разницы между свойством, использующим стандартные методы получения и установки, и необработанным атрибутом, за исключением того, что необработанный атрибут работает быстрее, потому что он использует базовый язык, а не вызывает методы. Функционально они идентичны. Единственный способ нарушения инкапсуляции - это если вы считаете, что круглые скобки (obj.set_attr('foo')) по своей природе превосходят знаки равенства (obj.attr = 'foo'). Публичный доступ - это публичный доступ. - person jcdyer; 16.10.2009
comment
@jcdyer столько контроля да, но не столько читабельности, другие часто ошибочно полагают, что obj.attr = 'foo' просто устанавливает переменную, и ничего больше не происходит - person Timo Huovinen; 10.08.2013
comment
@TimoHuovinen Чем это отличается от пользователя в Java, если предположить, что obj.setAttr('foo') просто устанавливает переменную, и больше ничего не происходит? Если это общедоступные методы, то это общедоступный метод. Если вы используете его для достижения какого-либо побочного эффекта, и он является общедоступным, тогда вам лучше рассчитывать на то, что все работает , как если бы произошел только этот предполагаемый побочный эффектall другие детали реализации и другие побочные эффекты, использование ресурсов, что угодно, скрытые от опасений пользователя). С Python это абсолютно не отличается. Синтаксис Python для достижения эффекта просто проще. - person ely; 17.10.2014

Спасибо, это действительно прояснило мои мысли. Вот (почти) 10 (почти) веских причин НЕ использовать геттеры и сеттеры:

  1. Когда вы поймете, что вам нужно сделать больше, чем просто установить и получить значение, вы можете просто сделать поле закрытым, и вы сразу же узнаете, где вы непосредственно к нему обратились.
  2. Любая проверка, которую вы выполняете там, может быть только контекстно-свободной, что на практике встречается редко.
  3. Вы можете изменить установленное значение - это настоящий кошмар, когда вызывающий передает вам значение, которое они [ужас шок] хотят, чтобы вы сохранили КАК ЕСТЬ.
  4. Вы можете скрыть внутреннее представление - фантастика, значит, вы убедитесь, что все эти операции симметричны, верно?
  5. Вы изолировали свой общедоступный интерфейс от изменений под листами - если вы разрабатывали интерфейс и не были уверены, подходит ли прямой доступ к чему-либо, то вам следовало продолжить проектирование.
  6. Некоторые библиотеки ожидают этого, но не многие - отражение, сериализация, фиктивные объекты прекрасно работают с общедоступными полями.
  7. Унаследовав этот класс, вы можете переопределить функциональность по умолчанию - другими словами, вы можете ДЕЙСТВИТЕЛЬНО сбить с толку вызывающих, не только скрывая реализацию, но и делая ее несовместимой.

Последние три я просто ухожу (N / A или D / C) ...

person Community    schedule 27.03.2012
comment
Я думаю, что решающим аргументом является то, что, если вы разрабатывали интерфейс и не были уверены, что прямой доступ к чему-либо в порядке, тогда вам следовало продолжать проектирование. Это самая важная проблема с геттерами / сеттеры: они уменьшают класс до простого контейнера (более или менее) общедоступных полей. Однако в реальном ООП объект - это больше, чем контейнер полей данных. Он инкапсулирует состояние и алгоритмы для управления этим состоянием. Что важно в этом утверждении, так это то, что состояние должно быть инкапсулировано и им можно управлять только с помощью алгоритмов, предоставляемых объектом. - person sbi; 24.08.2012

Что ж, я просто хочу добавить, что даже если иногда они необходимы для инкапсуляции и безопасности ваших переменных / объектов, если мы хотим закодировать настоящую объектно-ориентированную программу, нам нужно ПРЕКРАТИТЕ ИСПОЛЬЗОВАНИЕ АКСЕССУАРОВ, потому что иногда мы сильно зависим от них, когда на самом деле не требуется, и это делает почти то же самое, как если бы мы сделали переменные общедоступными.

person Jorge Aguilar    schedule 22.08.2012

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

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

Также с разным количеством циклов геттер работает немного быстрее, чем обычный способ. Надеюсь, это вам помогло.

person kangalioo    schedule 30.08.2016
comment
Заметные накладные расходы связаны с вызовом функции для доступа к памяти вместо простой загрузки адреса объекта и добавления смещения для доступа к членам. Скорее всего, виртуальная машина все равно оптимизировала ваш геттер. Тем не менее, упомянутые накладные расходы не стоят того, чтобы терять все преимущества геттеров / сеттеров. - person Alex; 06.09.2016

РЕДАКТИРОВАТЬ: Я ответил на этот вопрос, потому что есть множество людей, изучающих программирование, которые задают этот вопрос, и большинство ответов очень технически компетентны, но их не так легко понять, если вы новичок. Мы все были новичками, поэтому я подумал, что попробую найти более дружелюбный для новичков ответ.

Двумя основными из них являются полиморфизм и проверка. Даже если это просто дурацкая структура данных.

Допустим, у нас есть этот простой класс:

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();
}

Большой! А теперь просто меняем Bottle на это:

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 вместо Bottle. И то, как эти бутылки справляются с подобными вещами, может быть разным. У вас могут быть бутылки, которые записывают свое состояние на диск при его изменении, или бутылки, которые сохраняются в базах данных SQL или GNU знает что еще.

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

И да, похоже, что мы переходим от очень простой идеи к быстрому получению более качественных ответов.

Учтите также, что вы не можете изменить вместимость бутылки. Теперь он высечен в камне. Вы можете сделать это с помощью int, объявив его final. Но если бы это был список, вы могли бы очистить его, добавить в него новые элементы и так далее. Нельзя ограничивать доступ прикосновением к внутренностям.

Есть еще третья вещь, о которой не все учли: геттеры и сеттеры используют вызовы методов. Это означает, что везде они выглядят как обычные методы. Вместо того, чтобы иметь странный специфический синтаксис для DTO и прочего, у вас везде одно и то же.

person Haakon Løtveit    schedule 29.11.2015
comment
Спасибо за первое приличное объяснение интерфейсов, которое я прочитал, без каких-либо ссылок на пульты дистанционного управления или автомобили. - person djvs; 10.02.2016
comment
У вас могут быть бутылки, которые записывают свое состояние на диск при его изменении, или бутылки, которые сохраняются в базах данных SQL, которые я так сильно накачал xD. Но в любом случае, хорошая идея подарить это! - person Xerus; 18.10.2017

Мы используем геттеры и сеттеры:

  • для многоразового использования
  • для выполнения проверки на более поздних этапах программирования

Методы получения и установки - это общедоступные интерфейсы для доступа к частным членам класса.


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

Мантра инкапсуляции - сделать поля приватными, а методы общедоступными.

Методы получения. Мы можем получить доступ к закрытым переменным.

Методы установки. Мы можем изменять личные поля.

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

  • лучше;
  • безопаснее; а также
  • Быстрее.

Везде, где можно использовать значение, можно добавить метод, возвращающий это значение. Вместо того:

int x = 1000 - 500

использовать

int x = 1000 - class_name.getValue();

С точки зрения непрофессионала

Представление класса Person

Предположим, нам нужно сохранить детали этого Person. В этом Person есть поля name, age и sex. Для этого нужно создать методы для name, age и sex. Теперь, если нам нужно создать другого человека, необходимо заново создать методы для name, age, sex.

Вместо этого мы можем создать bean class(Person) с методами получения и установки. Так что завтра мы можем просто создавать объекты этого Бина class(Person class) всякий раз, когда нам нужно добавить нового человека (см. Рисунок). Таким образом, мы повторно используем поля и методы класса bean-компонента, что намного лучше.

person Devrath    schedule 02.09.2013

Я долго размышлял над этим в случае Java, и я считаю, что настоящие причины таковы:

  1. Код интерфейса, а не реализация
  2. Интерфейсы определяют только методы, а не поля

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

Это печально известные методы получения и установки ....

person Thorbjørn Ravn Andersen    schedule 07.11.2009
comment
Хорошо, второй вопрос; в случае, если это проект, в котором вы никому не экспортируете исходный код, и у вас есть полный контроль над источником ... получаете ли вы что-нибудь с помощью геттеров и сеттеров? - person Dean J; 09.11.2009
comment
В любом нетривиальном Java-проекте вам нужно кодировать интерфейсы, чтобы сделать вещи управляемыми и тестируемыми (подумайте о макетах и ​​прокси-объектах). Если вы используете интерфейсы, вам нужны геттеры и сеттеры. - person Thorbjørn Ravn Andersen; 09.11.2009

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

Думайте просто, легко, при необходимости добавляйте сложности.

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

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

person Mohamed    schedule 14.07.2012

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

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

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

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

    protected YourType _yourName = null;
    public YourType YourName{
      get
      {
        if (_yourName == null)
        {
          _yourName = new YourType();
          return _yourName;
        }
      }
    }
person quillbreaker    schedule 14.10.2009
comment
Итак, геттер вызывает сеттер? - person icc97; 18.09.2014
comment
Я добавил образец кода того, как я делал это в прошлом - по сути, вы сохраняете фактический класс в защищенном члене, а затем возвращаете этот защищенный член в метод доступа get, инициализируя его, если он не инициализирован. - person quillbreaker; 19.09.2014
comment

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

  • для участников у вас есть только одна спецификация доступа для настройки и получения
  • для сеттеров и геттеров вы можете настроить его и определить отдельно
person jdehaan    schedule 14.10.2009

В языках, которые не поддерживают «свойства» (C ++, Java) или требуют перекомпиляции клиентов при изменении полей на свойства (C #), использование методов get / set легче изменить. Например, добавление логики проверки к методу setFoo не потребует изменения открытого интерфейса класса.

В языках, поддерживающих «настоящие» свойства (Python, Ruby, может быть, Smalltalk?), Нет смысла получать / устанавливать методы.

person John Millikin    schedule 14.10.2009
comment
Re: C #. Если вы добавите функциональность к get / set, разве это не потребует перекомпиляции? - person steamer25; 14.10.2009
comment
@ steamer25: извините, набрал неправильно. Я имел ввиду, что клиентов класса придется перекомпилировать. - person John Millikin; 14.10.2009
comment
Добавление логики проверки к методу setFoo не требует изменения интерфейса класса на уровне языка, но меняет фактический интерфейс, также известный как контракт, потому что он изменяет предварительные условия. Почему нужно, чтобы компилятор не рассматривал это как критическое изменение , когда это так? - person R. Martinho Fernandes; 26.09.2012
comment
@ R.MartinhoFernandes, как исправить эту неработающую проблему? Компилятор не может сказать, сломалась она или нет. Это вызывает беспокойство только тогда, когда вы пишете библиотеки для других, но вы делаете это как универсальный zOMG, вот драконы! - person Phil; 29.10.2013
comment
Требование перекомпиляции, как упоминалось в ответе, - это один из способов, которым компилятор может сообщить вам о возможном критическом изменении. И почти все, что я пишу, фактически является библиотекой для других, потому что я работаю не один. Я пишу код, у которого есть интерфейсы, которые будут использовать другие участники проекта. Какая разница? Черт, даже если я буду пользователем этих интерфейсов, почему я должен придерживаться более низких стандартов качества в своем коде? Я не люблю работать с проблемными интерфейсами, даже если их пишу я. - person R. Martinho Fernandes; 30.10.2013
comment
Objective-C использует аннотации для обозначения свойств. Если программист класса не предоставляет методов доступа (получателей / установщиков) для аннотированной переменной-члена, такие методы синтезируются автоматически. Программист-автор всегда может вернуться и предоставить реализацию аксессора в любое время, когда она пожелает. Я понятия не имею, почему Java не приняла такое простое решение проблемы отсутствия свойств. - person Basil Bourque; 30.08.2018

Один из основных принципов объектно-ориентированного проектирования: Инкапсуляция!

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

person Justin Niessner    schedule 14.10.2009
comment
Геттеры и сеттеры инкапсуляции смехотворно тонкие. См. здесь. - person sbi; 24.08.2012
comment
Если в вашем общедоступном интерфейсе указано, что 'foo' имеет тип 'T' и может иметь любое значение, вы никогда не сможете это изменить. В последнем случае вы не можете решить сделать его типа «Y», а также не можете наложить такие правила, как ограничения по размеру. Таким образом, если у вас есть общедоступные команды get / set, которые ничего не делают для set / get, вы не получаете ничего, чего не предлагало бы публичное поле, что делает его более громоздким в использовании. Если у вас есть ограничение, например, для объекта может быть установлено значение null или значение должно быть в пределах диапазона, тогда да, потребуется метод общедоступного набора, но вы все равно представляете контракт на установку этого значения, которое может ' т изменить - person thecoshman; 03.05.2013
comment
Почему нельзя изменить контракт? - person Phil; 30.10.2013
comment
Почему все должно продолжать компилироваться, если контракты меняются? - person R. Martinho Fernandes; 30.10.2013

Вы должны использовать геттеры и сеттеры, когда:

  • You're dealing with something that is conceptually an attribute, but:
    • Your language doesn't have properties (or some similar mechanism, like Tcl's variable traces), or
    • Поддержки свойств вашего языка недостаточно для этого варианта использования, или
    • Идиоматические соглашения вашего языка (а иногда и вашего фреймворка) поощряют геттеры или сеттеры для этого варианта использования.

Так что это очень редко общий объектно-ориентированный вопрос; это вопрос, относящийся к конкретному языку, с разными ответами для разных языков (и разными вариантами использования).


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

Другими словами: если вы считаете, что потребители вашего класса не должны даже знать, что у вас есть атрибут spam, а тем более иметь возможность изменить его волей-неволей, то предоставление им метода set_spam - это последнее, что вы хотите сделать.

* Даже для этого простого класса вам не обязательно разрешать установку значений x и y. Если это действительно класс, разве у него не должно быть таких методов, как translate, rotate и т. Д.? Если это всего лишь класс, потому что в вашем языке нет записей / структур / именованных кортежей, то на самом деле это не вопрос объектно-ориентированного подхода…


Но никто и никогда не занимается общим объектно-ориентированным дизайном. Они занимаются дизайном и реализацией на определенном языке. А в некоторых языках геттеры и сеттеры далеко не бесполезны.

Если в вашем языке нет свойств, то единственный способ представить что-то, что концептуально является атрибутом, но фактически вычисляется, проверяется и т. Д., - это использовать методы получения и установки.

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

Что касается вопроса «что, если я захочу изменить свою реализацию позже?» вопрос (который повторяется несколько раз в разных формулировках как в вопросе OP, так и в принятом ответе): если это действительно чистое изменение реализации, и вы начали с атрибута, вы можете изменить его на свойство, не затрагивая интерфейс. Если, конечно, ваш язык этого не поддерживает. Так что это действительно тот же случай.

Кроме того, важно следовать идиомам языка (или фреймворка), который вы используете. Если вы напишете красивый код в стиле Ruby на C #, у любого опытного разработчика C #, кроме вас, будут проблемы с его чтением, а это плохо. Некоторые языки имеют более сильную культуру вокруг своих соглашений, чем другие. - и, возможно, не случайно, что Java и Python, которые находятся на противоположных концах спектра идиоматических геттеров, имеют две из самых сильных культур.

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

person abarnert    schedule 19.08.2014

С точки зрения объектно-ориентированного дизайна обе альтернативы могут нанести ущерб сопровождению кода из-за ослабления инкапсуляции классов. Для обсуждения вы можете заглянуть в эту отличную статью: http://typicalprogrammer.com/?p=23

person andrers52    schedule 30.04.2012

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

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

int getVar() const { return var ; }

Так что у тебя есть:

doSomething( obj->getVar() ) ;

Вместо того

doSomething( obj->var ) ;

Это не только getVar() визуально шумно, но и создает иллюзию того, что gettingVar() является каким-то более сложным процессом, чем он есть на самом деле. То, как вы (как автор класса) относитесь к святости var, особенно сбивает с толку пользователя вашего класса, если у него есть установщик passthru - тогда похоже, что вы устанавливаете эти ворота, чтобы «защитить» то, что, по вашему мнению, является ценным. , (святость var), но, тем не менее, даже вы признаете, что защита var ничего не стоит из-за того, что кто-то может просто войти и set var получить любую ценность, которую он хочет, без того, чтобы вы даже посмотрели на то, что они делают.

Поэтому я программирую следующим образом (предполагая «гибкий» подход - то есть когда я пишу код, не зная точно, что он будет делать / у меня нет времени или опыта, чтобы спланировать сложный интерфейс в стиле водопада. установленный):

1) Начните со всех публичных членов для основных объектов с данными и поведением. Вот почему во всем моем "примере" кода на C ++ вы заметите, что я везде использую struct вместо class.

2) Когда внутреннее поведение объекта для члена данных становится достаточно сложным (например, ему нравится сохранять внутренний std::list в некотором порядке), пишутся функции типа доступа. Поскольку я программирую сам, я не всегда сразу устанавливаю член private, но где-то в процессе развития класса член будет «повышен» до protected или private.

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

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

person bobobobo    schedule 05.05.2013
comment
... четко определенный интерфейс, с которым нельзя просто прикрутить внутренности и проверку в сеттерах. - person Agi Hammerthief; 18.12.2014

Геттеры и сеттеры используются для реализации двух фундаментальных аспектов объектно-ориентированного программирования, а именно:

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

Предположим, у нас есть класс Employee:

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();
    }
 }

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

person Pritam Banerjee    schedule 10.12.2015
comment
Для меня бесполезно иметь тонны геттеров и сеттеров, которые не делают ничего уникального. getFullName - исключение, потому что он делает что-то еще. Открытие только трех переменных и сохранение getFullName упростят чтение программы, но при этом полное имя будет скрыто. Как правило, я полностью согласен с геттерами и сеттерами, если. они делают что-то уникальное и / или b. у вас только один, да, у вас может быть публичный финал и все такое, но нет - person FacelessTiger; 14.12.2016
comment
Преимущество этого заключается в том, что вы можете изменять внутреннюю структуру класса, не меняя интерфейс. Скажем, вместо трех свойств у вас было одно - массив строк. Если вы использовали геттеры и сеттеры, вы можете внести это изменение, а затем обновить геттеры / сеттеры, чтобы знать, что имена [0] - это имя, имена [1] - среднее и т. Д. Но если вы просто использовали общедоступные свойства , вам также придется изменить каждый класс, к которому осуществляется доступ Employee, потому что свойство firstName, которое они использовали, больше не существует. - person Andrew Hows; 08.12.2017
comment
@AndrewHows из того, что я видел в реальной жизни, когда люди меняют внутреннюю часть класса, они также меняют интерфейс и проводят большой рефакторинг всего кода - person Heetola; 06.05.2020

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

У использования методов получения и установки есть некоторые преимущества, например, возможность создавать члены со сложной функциональностью, к которым вы можете получить доступ, например к свойствам. Они также позволяют создавать свойства только для чтения и только для записи.

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

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

person Sumit Singh    schedule 30.08.2012

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

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
person GeZo    schedule 13.05.2014

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

person Jason Baker    schedule 14.10.2009
comment
Я бы никогда не ожидал, что геттер или сеттер будут дорогостоящими операциями. В таких случаях лучше использовать фабрику: используйте все необходимые сеттеры, а затем вызовите дорогостоящий метод execute или build. - person Hubert Grzeskowiak; 01.08.2016

Одно относительно современное преимущество геттеров / сеттеров заключается в том, что они упрощают просмотр кода в редакторах тегированного (индексированного) кода. Например. Если вы хотите увидеть, кто устанавливает член, вы можете открыть иерархию вызовов установщика.

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

person Rakesh Singh    schedule 03.01.2017
comment
вы можете щелкнуть правой кнопкой мыши ›найти использование на члене точно так же, как на геттере / сеттере - person Heetola; 06.05.2020

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

person Antz    schedule 14.10.2009

Кроме того, это сделано для «будущего» вашего класса. В частности, переход от поля к свойству является нарушением ABI, поэтому, если вы позже решите, что вам нужно больше логики, чем просто «установить / получить поле», тогда вам нужно сломать ABI, что, конечно, создает проблемы для чего угодно. остальное уже скомпилировано для вашего класса.

person Pete    schedule 14.10.2009
comment
Я полагаю, что изменение поведения геттера или сеттера не является критическим изменением. - person R. Martinho Fernandes; 26.09.2012
comment
@ R.MartinhoFernandes не всегда должен быть таким. TBYS - person Phil; 29.10.2013

Я просто хотел бы подкинуть идею аннотации: @getter и @setter. С @getter вы должны иметь возможность obj = class.field, но не class.field = obj. С @setter наоборот. С @getter и @setter вы сможете делать и то, и другое. Это сохранит инкапсуляцию и сократит время, не вызывая тривиальные методы во время выполнения.

person fastcodejava    schedule 14.10.2009
comment
Это будет реализовано во время выполнения с помощью тривиальных методов. На самом деле, наверное, нетривиально. - person Phil; 29.10.2013
comment
Сегодня это можно сделать с помощью препроцессора аннотаций. - person Thorbjørn Ravn Andersen; 07.01.2018

Я могу придумать одну причину, по которой вы бы не хотели, чтобы все было публично.

Например, переменная, которую вы никогда не собирались использовать вне класса, может быть доступна даже напрямую через доступ к цепочке переменных (например, object.item.origin.x).

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

person MongooseLover    schedule 15.12.2013
comment
Ярким примером этого является случай, когда установка значения одного атрибута влияет на одно или несколько других значений атрибута. Тривиальный пример: предположим, что вы сохраняете радиус окружности. Использование circ.set_radius () `на самом деле ничего не дает, установка радиуса напрямую через circ.radius не дает. Однако get_diameter (), get_circumference () и get_area () могут выполнять вычисления на основе радиуса. Без геттеров вы должны сами выполнить вычисления и проверить их правильность. - person Agi Hammerthief; 18.12.2014

Геттеры и сеттеры из сокрытия данных. Скрытие данных означает, что мы скрываем данные от посторонних или постороннее лицо / объект не может получить доступ к нашим данным. Это полезная функция в ООП.

В качестве примера:

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

public и private - модификаторы доступа.

Итак, как мы можем получить доступ к этой переменной извне:

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

Пример (Java):

private String name;

public String getName(){
   return this.name;
}

public void setName(String name){
   this.name= name;
}

Преимущество:

Когда кто-либо хочет получить доступ или изменить / установить значение переменной balance, он / она должны иметь разрешение.

//assume we have person1 object
//to give permission to check balance
person1.getName()

//to give permission to set balance
person1.setName()

Вы также можете установить значение в конструкторе, но когда позже вы захотите обновить / изменить значение, вы должны реализовать метод установки.

person Blasanka    schedule 22.04.2017
comment
ваш getBalance / setBalance не является геттером / сеттером, если у них есть другой код, не так ли? И зачем выставлять баланс? Разве не было бы безопаснее иметь applyPayment или applyDebt, позволяющую проверять баланс, и, возможно, поле для заметок, чтобы указать, откуда был произведен платеж? Привет! Я просто улучшил ваш дизайн И удалил сеттер и получатель. В этом и заключается суть установщиков / получателей: они почти всегда улучшают ваш код, удаляя их, не то чтобы они были неправильными, просто они почти всегда приводят к худшему коду. Кстати, свойства (как в C #) имеют точно такую ​​же проблему. - person Bill K; 01.05.2017
comment
Мы разработчик, отсутствие сеттера / получателя ничего не защищает, мы можем просто добавить их .... - person Heetola; 06.05.2020

Есть разница между DataStructure и Object.

Datastructure должен раскрывать свое внутреннее, а не поведение.

Объект не должен открывать свои внутренности, но он должен раскрывать свое поведение, которое также известно как Закон Деметры.

В основном DTO считаются скорее структурой данных, а не объектом. Они должны раскрывать только свои данные, а не поведение. Наличие Setter / Getter в DataStructure раскрывает поведение, а не данные внутри него. Это еще больше увеличивает вероятность нарушения Закона Деметры.

Дядя Боб в своей книге «Чистый код» объяснил Закон Деметры.

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

Точнее, Закон Деметры гласит, что метод f класса C должен вызывать только следующие методы:

  • C
  • Объект, созданный f
  • Объект, переданный в качестве аргумента функции f
  • Объект, хранящийся в переменной экземпляра C

Метод не должен вызывать методы для объектов, возвращаемых какой-либо из разрешенных функций. Другими словами, разговаривайте с друзьями, а не с незнакомцами.

Итак, в соответствии с этим, примером нарушения LoD является:

final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();

Здесь функция должна вызывать метод своего непосредственного друга, который здесь ctxt. Она не должна вызывать метод своего непосредственного друга друга. но это правило не распространяется на структуру данных. Итак, здесь, если ctxt, option, scratchDir являются структурой данных, тогда зачем оборачивать их внутренние данные каким-либо поведением и нарушением LoD.

Вместо этого мы можем сделать что-то вроде этого.

final String outputDir = ctxt.options.scratchDir.absolutePath;

Это удовлетворяет наши потребности и даже не нарушает LoD.

В духе «Чистого кода» Роберта К. Мартина (дядя Боб)

person aditya lath    schedule 30.03.2021

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

Я думаю, что ООП все усложняет, поскольку программа растет, масштабирование для разработчика становится кошмаром.

Простой пример; мы генерируем заголовки c ++ из xml. Заголовок содержит простое поле, не требующее проверки. Но все же, поскольку в моде аксессуар OOPS, мы генерируем их следующим образом.

const Filed& getfield() const
Field& getField() 
void setfield(const Field& field){...} 

что очень многословно и не требуется. просто

struct 
{
   Field field;
};

достаточно и читабельно. В функциональном программировании нет концепции сокрытия данных, они даже не требуют этого, поскольку не изменяют данные.

person user982042    schedule 08.06.2021

Я хотел опубликовать реальный пример, который только что закончил:

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

package com.foo.entities.custom
class User extends com.foo.entities.User{
     public Integer getSomething(){
         return super.getSomething();             
     }
     public void setSomething(Integer something){
         something+=1;
         super.setSomething(something); 
     }
}

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

person ebt    schedule 08.07.2010
comment
То, что я сделал выше, - это переопределить существующие методы суперкласса моей новой функциональностью. С функциональностью, которая, как мы все надеемся, уже должным образом задокументирована для старого интерфейса, верно? В противном случае вы просто нарушили LSP и внесли незаметное критическое изменение, которое было бы обнаружено компилятором, если бы в поле зрения не было геттеров / сеттеров. - person R. Martinho Fernandes; 24.08.2012
comment
@ R.MartinhoFernandes ... а затем запустить инструменты гибернации, чтобы сгенерировать java-код, это не случай изменения поведения какого-то класса, это работа над дерьмовым инструментом. Возможно, контракт (который в данном случае находится в подклассе) всегда был для этого сюрпризом. Может быть аргументом в пользу has-a вместо is-a. - person Phil; 29.10.2013
comment
Я не понимаю, чего вы достигли, если не использовали свойства суперкласса напрямую. - person Agi Hammerthief; 18.12.2014

Если вам нужна переменная только для чтения, но вы не хотите, чтобы клиент менял способ доступа к ней, попробуйте этот шаблонный класс:

template<typename MemberOfWhichClass, typename primative>                                       
class ReadOnly {
    friend MemberOfWhichClass;
public:
    template<typename number> inline bool   operator==(const number& y) const { return x == y; } 
    template<typename number> inline number operator+ (const number& y) const { return x + y; } 
    template<typename number> inline number operator- (const number& y) const { return x - y; } 
    template<typename number> inline number operator* (const number& y) const { return x * y; }  
    template<typename number> inline number operator/ (const number& y) const { return x / y; } 
    template<typename number> inline number operator<<(const number& y) const { return x << y; }
    template<typename number> inline number operator^(const number& y) const  { return x^y; }
    template<typename number> inline number operator~() const                 { return ~x; }
    template<typename number> inline operator number() const                  { return x; }
protected:
    template<typename number> inline number operator= (const number& y) { return x = y; }       
    template<typename number> inline number operator+=(const number& y) { return x += y; }      
    template<typename number> inline number operator-=(const number& y) { return x -= y; }      
    template<typename number> inline number operator*=(const number& y) { return x *= y; }      
    template<typename number> inline number operator/=(const number& y) { return x /= y; }      
    primative x;                                                                                
};      

Пример использования:

class Foo {
public:
    ReadOnly<Foo, int> cantChangeMe;
};

Помните, что вам также необходимо добавить побитовые и унарные операторы! Это просто для начала

person Jonathan    schedule 01.04.2014
comment
Обратите внимание, что вопрос был задан без привязки к конкретному языку. - person Hubert Grzeskowiak; 01.08.2016

Одно относительно современное преимущество геттеров / сеттеров заключается в том, что они упрощают просмотр кода в редакторах тегированного (индексированного) кода. Например. Если вы хотите увидеть, кто устанавливает член, вы можете открыть иерархию вызовов установщика.

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

person jfritz42    schedule 06.05.2014

Хотя эти методы не являются обычным явлением для геттеров и сеттеров, их также можно использовать в шаблонах АОП / прокси. например, для аудита переменной вы можете использовать АОП для аудита обновления любого значения. Без геттера / сеттера это невозможно, кроме как повсюду менять код. Лично я никогда не использовал для этого АОП, но это показывает еще одно преимущество использования геттера / сеттера.

person Jean-Christophe Blanchard    schedule 04.02.2016

По моему опыту, идеально установить переменные как частные и предоставить средства доступа и модификаторы для каждой переменной.

Таким образом, вы можете создавать переменные только для чтения или записывать только переменные в зависимости от ваших требований.

Ниже реализация показывает переменную только для записи.

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

Ниже показана переменная только для чтения.

private String foo;
private void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return foo; }
person Lakindu Hewawasam    schedule 19.11.2020

Пусть код говорит сам за себя:

Mesh mesh = new Mesh();
BoundingVolume vol = new BoundingVolume();
mesh.boundingVolume = vol;
vol.mesh = mesh;
vol.compute(); 

Вам нравится это? Вот с сеттерами:

Mesh mesh = new Mesh();
BoundingVolume vol = new BoundingVolume();
mesh.setBoundingVolume(vol);
person luke1985    schedule 26.11.2013
comment
Вы не ответили на вопрос: в чем преимущество использования геттеров и сеттеров - которые только получают и устанавливают ... Ваш пример не относится к этому случаю, и поэтому ваш ответ не относится к этому вопросу . - person AgilePro; 28.10.2014
comment
Я считаю, что семантика приведенных примеров кода совершенно другая. В первом примере также создается круговая ссылка: mesh.boundingVolume.mesh == mesh. - person Hubert Grzeskowiak; 01.08.2016

Это хороший вопрос, на который есть еще лучшие ответы. Так как их много, я просто добавлю немного больше. Этот пример основан на C #, просто полезный фрагмент кода. Подтверждение данных в скобках уже объяснялось.

public class foo
{
    public int f1 { get; set; }             // A classic GS
    public int f2 { get; private set; }     // A GS with public read access, the write is only on the private level
    public int f3 { private get; set; }     // A GS where "You can set, but you can't get" outside the class
    public int f4 { get; set; } = 10;       // A GS with default value, this is a NEW feature of C# 6.0 / .NET 4.6
}
person Bartłomiej Sobieszek    schedule 22.08.2015
comment
В Java таких геттеров и сеттеров нет. У вас есть Project Lombok, в котором аннотации используются во многом с тем же эффектом. Так что, если вам нужна эта изящность, но на Java, а не на C #, тогда вы знаете, куда идти. :) - person Haakon Løtveit; 16.12.2015