Геттеры и сеттеры часто критикуются за то, что они не являются правильными. С другой стороны, большая часть кода OO, который я видел, содержит обширные методы получения и установки.
Когда получатели и установщики оправданы? Вы пытаетесь избежать их использования? Они чрезмерно используются в целом?
Если у вашего любимого языка есть свойства (у моего есть), то такие вопросы также считаются получателями и установщиками для этого вопроса. Это одно и то же с точки зрения методологии ОО. У них просто более приятный синтаксис.
Источники для Критики Геттера / Сеттера (некоторые взяты из комментариев, чтобы дать им лучшую видимость):
- http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html
- http://typicalprogrammer.com/?p=23
- http://c2.com/cgi/wiki?AccessorsAreEvil
- http://www.darronschall.com/weblog/2005/03/no-brain-getter-and-setters.cfm
- http://www.adam-bien.com/roller/abien/entry/encapsulation_violation_with_getters_and
- http://www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html
Чтобы сформулировать критику просто: геттеры и сеттеры позволяют вам манипулировать внутренним состоянием объектов извне объекта. Это нарушает инкапсуляцию. Только сам объект должен заботиться о его внутреннем состоянии.
И пример процедурной версии кода.
struct Fridge
{
int cheese;
}
void go_shopping(Fridge fridge)
{
fridge.cheese += 5;
}
Мутаторная версия кода:
class Fridge
{
int cheese;
void set_cheese(int _cheese) { cheese = _cheese; }
int get_cheese() { return cheese; }
}
void go_shopping(Fridge fridge)
{
fridge.set_cheese(fridge.get_cheese() + 5);
}
Получатели и установщики значительно усложнили код, не обеспечив надлежащую инкапсуляцию. Поскольку внутреннее состояние доступно для других объектов, мы не получаем много, добавляя эти методы получения и установки.
Вопрос был ранее обсужден на переполнении стека:
источник
Getters and setters are often criticized as being not proper OO
- Цитировать, пожалуйста.Ответы:
Наличие геттеров и сеттеров само по себе не нарушает инкапсуляцию. Что нарушает инкапсуляцию, так это автоматическое добавление метода получения и установки для каждого элемента данных (каждое поле в языке Java), не задумываясь об этом. Хотя это лучше, чем обнародовать все элементы данных, это всего лишь маленький шаг.
Суть инкапсуляции не в том, что вы не должны знать или изменять состояние объекта извне объекта, а в том, что у вас должна быть разумная политика для этого.
Некоторые члены данных могут быть полностью внутренними по отношению к объекту и не должны иметь ни методов получения, ни установки.
Некоторые члены данных должны быть доступны только для чтения, поэтому им могут потребоваться средства получения, но не средства установки.
Некоторые члены данных, возможно, должны быть согласованы друг с другом. В таком случае вы бы не предоставили установщик для каждого из них, а использовали бы один метод их одновременной настройки, чтобы можно было проверить значения на предмет согласованности.
Некоторые элементы данных могут быть изменены только определенным образом, например, увеличены или уменьшены на фиксированную величину. В этом случае вы бы указали метод
increment()
и / илиdecrement()
метод, а не метод установки.Тем не менее, другие могут фактически нуждаться в чтении-записи и иметь как геттер, так и сеттер.
Рассмотрим пример
class Person
. Допустим, у человека есть имя, номер социального страхования и возраст. Допустим, мы не позволяем людям когда-либо менять свои имена или номера социального страхования. Однако возраст человека должен увеличиваться на 1 каждый год. В этом случае вы бы предоставили конструктор, который бы инициализировал имя и SSN с заданными значениями, и который бы инициализировал возраст до 0. Вы также предоставили бы методincrementAge()
, который увеличил бы возраст на 1. Вы также предоставили бы добытчики для всех трех. В этом случае сеттеры не требуются.В этом проекте вы разрешаете проверять состояние объекта извне класса и разрешаете его изменение извне класса. Однако вы не допускаете произвольного изменения состояния. Существует политика, которая фактически гласит, что имя и SSN не могут быть изменены вообще, и что возраст может быть увеличен на 1 год за один раз.
Теперь скажем, у человека тоже есть зарплата. И люди могут менять работу по желанию, что означает, что их зарплата также изменится. Для моделирования этой ситуации у нас нет другого пути, кроме как предоставить
setSalary()
метод! Разрешение на изменение зарплаты по желанию является вполне разумной политикой в этом случае.Кстати, в вашем примере, я дал бы класс и методы, вместо и . Тогда у вас все равно будет инкапсуляция.
Fridge
putCheese()
takeCheese()
get_cheese()
set_cheese()
источник
Основная причина получения и установки в Java очень проста:
Следовательно, если вы хотите, чтобы поле проходило через интерфейс, вам понадобится ридер и метод записи. Они традиционно называются getX и setX для поля x.
источник
С http://www.adam-bien.com/roller/abien/entry/encapsulation_violation_with_getters_and
Стиль JavaBean:
OO-стиль:
Ну, ясно, что я предпочитаю последний подход; он не отбрасывает детали реализации, он проще и лаконичнее, а вся необходимая информация включена в вызов метода, поэтому проще понять его правильно. Я также предпочитаю устанавливать закрытые члены, используя параметры в конструкторе, когда это возможно.
Ваш вопрос: когда оправдан метод получения / установки? Возможно, когда необходимо изменить режим или вам нужно опросить объект для получения какой-либо информации.
Размышляя об этом, когда я впервые начал писать код на C #, я написал много кода в стиле Javabeans, показанном выше. Но когда я приобрел опыт работы с языком, я начал больше настраивать элементы в конструкторе и использовать методы, которые больше походили на описанный выше стиль ОО.
источник
Когда поведение «get» и «set» фактически соответствует поведению в вашей модели, чего практически никогда не бывает .
Любое другое использование - это просто обман, потому что поведение бизнес-сферы не совсем понятно.
редактировать
Этот ответ мог показаться легкомысленным, поэтому позвольте мне расширить. Ответы, приведенные выше, в основном правильные, но сфокусированы на парадигмах программирования ОО-дизайна и некоторых, которые упускают общую картину. По моему опыту, это заставляет людей думать, что избегание получения и установки - это некое академическое правило для языков программирования ОО (например, люди думают, что замена методов получения на свойства - это великое дело)
На самом деле это является следствием процесса проектирования. Вам не нужно вдаваться в интерфейсы, инкапсуляцию и шаблоны, споря о том, нарушает ли это эти парадигмы или нет, и что является хорошим или не является хорошим ОО-программированием. Единственное, что в конечном итоге имеет значение, - это то, что если в вашем домене нет ничего, что работает, добавляя их, вы не моделируете свой домен.
Реальность такова, что очень маловероятно, что любая система в вашем доменном пространстве имеет геттеры и сеттеры. Вы не можете подойти к мужчине или женщине, которые отвечают за выплату заработной платы, и просто сказать «Установите эту зарплату на Х» или «Получите мне эту зарплату» . Такого поведения просто не существует
Если вы помещаете это в свой код, вы не проектируете свою систему так, чтобы она соответствовала модели вашего домена. Да, это нарушает интерфейсы и инкапсуляцию, но это не главное. Дело в том, что вы моделируете то, чего не существует.
Более того, вы, вероятно, упускаете важный шаг или процесс, потому что, возможно, есть причина, по которой я не могу просто подойти к зарплате и сказать, установить эту зарплату на X.
Когда люди используют геттеры и сеттеры, они склонны толкать правила этого процесса в неправильное место. Это еще больше уходит от вашего домена. Используя пример из реального мира, это похоже на зарплату, если предположить, что случайный человек, который вошел, имеет разрешение на получение этих значений, иначе он не стал бы их просить. Мало того, что это не то, как домен, это на самом деле ложь о том, как домен.
источник
set/get
зарплата?Как правило, геттеры и сеттеры - плохая идея. Если поле не является логически частью интерфейса, и вы делаете его закрытым, это нормально. Если это логически часть интерфейса и вы делаете его публичным, это нормально. Но если вы сделаете его закрытым, а затем развернетесь и снова сделаете его эффективным, предоставив метод получения и установки, вы вернетесь к тому, с чего начали, за исключением того, что ваш код теперь более многословен и запутан.
Очевидно, есть исключения. В Java вам может понадобиться использовать интерфейсы. Стандартная библиотека Java предъявляет требования обратной совместимости настолько экстремальные, что перевешивают обычные показатели качества кода. Возможно даже, что вы на самом деле имеете дело с легендарным, но редким случаем, когда есть большая вероятность, что вы позже сможете заменить сохраненное поле на лету, не нарушая интерфейс. Но это исключения. Геттеры и сеттеры - это анти-паттерн, который нуждается в особом обосновании.
источник
является ли поле доступным напрямую или через метод, не очень важно.
Классовые инварианты (полезные) важны. И чтобы сохранить их, нам иногда не нужно что-то менять извне. Например. если у нас есть класс Square с раздельными шириной и высотой, изменение одного из них превращает его в нечто иное, чем квадрат. Поэтому нам нужен метод changeSide. Если бы это был Rectangle, у нас могло бы быть setters / public field. Но setter than проверяет, будет ли его значение больше нуля.
И в конкретных языках (например, Java) есть причины, по которым нам нужны эти методы (интерфейсы). И еще одна причина метода - совместимость (исходная и двоичная). Поэтому их легче добавить, а затем подумать, будет ли достаточно публичного поля.
Кстати. Мне нравится использовать простые неизменяемые значения, содержащие классы с открытыми конечными полями.
источник
Возможно, вы захотите поменять свои внутренние устройства на что угодно, сохраняя интерфейсы такими же. Если ваши интерфейсы не меняются, их код не сломается. Вы все еще можете изменить свои внутренние органы, как вы хотите.
источник
Мой подход заключается в следующем -
Когда я ожидаю, что получу данные позже, получатель / установщик оправдан. Кроме того, если происходят изменения, я часто помещаю данные в метод получения / установки.
Если это структура POD, я оставляю слоты доступными.
На более абстрактном уровне вопрос заключается в том, «кто управляет данными», и это зависит от проекта.
источник
Если использование геттеров и сеттеров кажется сложным, проблема может заключаться в языке, а не в самой концепции.
Вот код из второго примера, написанного на Ruby:
Заметьте, это очень похоже на первый пример в Java? Когда геттеры и сеттеры рассматриваются как первоклассные граждане, их использование не является рутиной, и дополнительная гибкость иногда может быть настоящим благом - например, мы можем решить вернуть значение по умолчанию для сыра в новом холодильнике:
Конечно, будет много переменных, которые вообще не должны публиковаться. Излишняя демонстрация внутренних переменных сделает ваш код хуже, но вы вряд ли можете обвинить это в методах получения и установки.
источник
Рассмотрим
Size
класс, который инкапсулирует ширину и высоту. Я могу устранить сеттеры с помощью конструктора, но как это поможет мне нарисовать прямоугольникSize
? Ширина и высота не являются внутренними данными для класса; это общие данные, которые должны быть доступны потребителям Size.Объекты состоят из поведения и состояния - или атрибутов. Если нет открытого состояния, то только поведение является публичным.
Без состояния, как бы вы отсортировали коллекцию объектов? Как бы вы искали конкретный экземпляр объекта? Если вы используете только конструкторы, что произойдет, если у вашего объекта длинный список атрибутов?
Ни один параметр метода никогда не должен использоваться без проверки. Поэтому лень писать
Если вы пишете это таким образом, вы по крайней мере подготовились к использованию установщика для проверки; это лучше, чем публичное поле - но едва. Но, по крайней мере, у вас есть непротиворечивый общедоступный интерфейс, который вы можете вернуть и ввести в правила проверки, не нарушая код ваших клиентов.
Геттеры, сеттеры, свойства, мутаторы, называйте их как хотите, но они необходимы.
источник
int
например, переменную экземпляра, и представьте, что вы решили добавить правило проверки, которое принимает только неотрицательные значения. Проблема в том, что код вашего клиента уже может полагаться на возможность установить его в отрицательное значение ...Если геттеры и сеттеры нарушают инкапсуляцию и истинное ОО, у меня серьезные проблемы.
Я всегда чувствовал, что объект представляет собой то, что приходит на ум лучше всего, что вам нужно для этого.
Я только что закончил писать программу, которая генерирует Лабиринты на Java, и у меня есть класс, который представляет «Квадраты лабиринта». У меня есть данные в этом классе, которые представляют координаты, стены и логические значения и т. Д.
У меня должен быть какой-то способ изменить / манипулировать / получить доступ к этим данным! Что мне делать без геттеров и сеттеров? Java не использует свойства, и установка всех моих данных, которые являются локальными для этого класса, на общедоступные, является ОПРЕДЕЛЕННО нарушением инкапсуляции и ОО.
источник
Во-первых, в общих чертах есть два типа объектов, которые я буду комментировать, типы значений и сервисы.
Типы служб никогда не должны иметь установщиков, какие бы зависимости они не требовали, они не должны быть доступными Лучший способ передачи зависимостей - через конструктор или фабрику, чтобы все экземпляры были полностью сформированы с самого начала, простым и понятным.
Типы значений также должны быть неизменяемыми, с другой стороны, бывают случаи, когда это нецелесообразно, например, ORM или какое-либо другое отображение, например, из виджета в объект. Все другие типы значений, которые передаются по системе от одного слоя или части к другому, должны быть неизменяемыми и не должны иметь установщиков.
источник
Метод получения / установки оправдан, как и любой другой публичный метод. Обоснование в основном потому, что мы хотим предоставить интерфейс с внешним миром, который определяет, как наш класс взаимодействует с другими классами. Мы делаем это главным образом потому, что хотим уменьшить связь между отдельными объектами. Уменьшить сцепление - хорошая вещь по многим причинам:
источник
Да, геттеры и сеттеры являются анти-паттернами в объектно-ориентированном программировании и никогда не должны использоваться: http://www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html . Короче говоря, они не вписываются в объектно-ориентированную парадигму, потому что они побуждают вас относиться к объекту как к структуре данных. Что является серьезным заблуждением.
источник
Я надеюсь, что все, что IDE, разработанная компанией, которая разрабатывает ваш язык программирования автоматически, не нарушает «Принципы объектной ориентации».
Тем не менее, всякий раз, когда у вас есть общедоступная переменная в области видимости, используйте геттер и сеттер, и вы великолепны. Мне кажется, что это необходимый элемент чрезвычайно объектно-ориентированного принципа инкапсуляции, даже если он выглядит просто как много ненужного кода.
Причиной их использования является то, что правильная инкапсуляция еще может иметь место, и пока вы абстрагируете слой, который позволяет человеку, манипулирующему вашим объектом, чувствовать ваш объект, вы можете убрать этот объект, даже не зная, верно?
Достаточно сказать, что разделенный дом не может стоять, один из арендаторов ОО не собирается сам включаться, и вы не можете обслуживать как инкапсуляцию, так и преждевременную оптимизацию.
источник
Я думал, что у нас будут более обычные ответы здесь?
Геттеры и сеттеры в целом чрезвычайно ООП (любой, кто говорит что-то еще, не прав, просто так).
Хотя вы должны помнить, чтобы не перепутать инженера, никогда не делайте геттер или сеттер, которые не нужны. Любая информация, которую вы не собираетесь использовать другим классом, не должна иметь какого-либо метода получения или установки.
Однако причина, по которой вы не делаете поля общедоступными, а вместо этого получаете геттеры и сеттеры, в основном:
Невозможно сделать правильные тесты, используя поля. Геттеры / сеттеры намного лучше в этом отношении.
Невозможно правильно использовать поля в режиме программирования в реальном времени. Синхронизированные методы получения / установки - путь.
Тема интерфейса (уже объяснил, поэтому не буду).
Это проще в использовании при правильном повторном использовании системы.
Гораздо сложнее узнать, какие классы используют ваш класс и что сломается, если вы измените поле, чем метод получения / установки.
Поэтому единственный раз, когда вы используете открытое поле вместо получателя / установщика, это когда вы не делаете официальный проект, а просто делаете это для развлечения и не можете беспокоиться о получателе / установщике.
источник