Аллен Голуб написал: «Никогда не следует использовать функции get/set», он прав?[дубликат]

StackOverflow https://stackoverflow.com/questions/996179

Вопрос

На этот вопрос уже есть ответ здесь:

Аллен Голуб написал следующее:

Вы не можете иметь программу без какой-либо связи.Тем не менее, вы можете значительно минимизировать связанность, рабски следуя принципам объектно-ориентированного подхода (самым важным является то, что реализация объекта должна быть полностью скрыта от объектов, которые его используют).Например, переменные экземпляра объекта (поля-члены, которые не являются константами) всегда должны быть закрытыми.Период.Без исключений.Всегда.Я серьезно.(Иногда вы можете эффективно использовать защищенные методы, но защищенные переменные экземпляра — это мерзость.)

Это звучит разумно, но затем он продолжает:

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

Что, честно говоря, для меня звучит просто безумием.

Я понимаю принцип сокрытия информации, но без аксессоров и мутаторов вы вообще не сможете использовать Java-бины.Я не знаю, как бы вы следовали проекту MVC без аксессоров в модели, поскольку модель не могу нести ответственность за рендеринг представления.

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

Статьи Аллена Голуба для справки


Связанные вопросы:

Это было полезно?

Решение

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

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

Голуб не верит, что вы заметили разницу.Я думаю, что именно знание разницы делает тебя профессионалом.

Другие советы

Прочтите внимательно эту статью.Голуб настаивает на том, что геттеры и сеттеры — это злой «антишаблон по умолчанию», плохая привычка, к которой мы прибегаем при проектировании системы;потому что мы можем.

Мыслительный процесс должен быть последовательным;Что означает этот объект делать?Каковы его обязанности?Каково его поведение?Что оно знает?Долгое и упорное размышление над этими вопросами естественным образом приведет вас к разработке классов, которые предоставляют интерфейс максимально высокого уровня.

Автомобиль является хорошим примером.Он предоставляет четко определенный, стандартизированный интерфейс высокого уровня.меня не волнует setSpeed(60)...это мили в час или км/ч?Я просто ускоряюсь, двигаюсь, замедляюсь.Мне не нужно думать о деталях в setSteeringWheelAngle(getSteeringWheelAngle()+Math.rad(-1.5)), Я просто turn(-1.5), и детали позаботятся о под капотом.

Это сводится к следующему: «Вы можете и должны выяснить, для чего будет использоваться каждый класс, что он делает, что представляет, и предоставить интерфейс самого высокого уровня, который соответствует этим требованиям.Геттеры и сеттеры обычно являются отговоркой, когда программисту просто лениво проводить анализ, необходимый для точного определения того, чем является каждый класс, а чем не является, и поэтому мы идем по пути «он может делать все что угодно».Геттеры и сеттеры — это зло!

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

Это менталитет, который он продвигает.Геттеры и сеттеры — это легкая ловушка, в которую легко попасть.

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

daisy.setColor(Color.PINK) имеет смысл.Что еще можно сделать?Возможно, вулканец объединил разумы, чтобы создать цветок. хотеть быть розовым?Хм?

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

Я думаю, что то, что пытался сказать Аллен Голуб, перефразировав на этот статья, заключается в следующем.

Геттеры и сеттеры могут быть полезны для переменных, которые вы хотите инкапсулировать, но вам не обязательно использовать их для всех переменных.На самом деле, использование их для всех переменных — это неприятный запах кода.

Проблема программистов, и Аллен Голуб был прав, отметив это, заключается в том, что они иногда используют методы получения/установки для всех переменных.И цель инкапсуляции теряется.

(обратите внимание, что я подхожу к этому с точки зрения «свойства» .NET)

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

Хорошо, аргументы метода можно изменить как расширяющие преобразования, но...просто почему...Также обратите внимание, что в C# var Ключевое слово может смягчить большую часть этой воспринимаемой боли.

Аксессоры нет деталь реализации;они являются общедоступным API/контрактом.Да, если вы нарушите контракт, у вас будут проблемы.Когда это стало сюрпризом?Аналогично, средства доступа нередко бывают нетривиальными, т.е.они делают больше, чем только перенос полей;они выполняют вычисления, логические проверки, уведомления и т. д.И они позволяют абстрагировать состояние на основе интерфейса.Да, и полиморфизм и т. д.

О подробном характере средств доступа (p3?4?) - в C#: public int Foo {get; private set;} - Работа выполнена.

В конечном счете, весь код — это средство выражения наших намерений компилятору.Свойства позволяют мне делать это типобезопасным, основанным на контрактах, проверяемым, расширяемым и полиморфным способом — спасибо.Зачем мне это «исправлять»?

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

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

Я дополнительно погуглил Аллена Голуба, кажется, у него есть своя доля противников в сообществе Java.

Последнее особенно заметно.Текст комментатора выделен курсивом.

Хотя getIdentity начинается с «get», это не метод доступа, поскольку он не просто возвращает поле.Он возвращает сложный объект с разумным поведением.

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

Кроме того, я заметил, что Аллен радикально смягчил свою позицию по сравнению с его предыдущей колонкой на ту же тему, где мантра «Никогда не используйте средства доступа» не претерпела ни одного исключения.Возможно, через несколько лет он понял, что аксессуары все-таки служат своей цели...

Имейте в виду, что на самом деле я не добавлял никакого кода пользовательского интерфейса в бизнес-логику.Я написал уровень пользовательского интерфейса с использованием AWT (Abstract Window Toolkit) или Swing, которые оба являются уровнями абстракции.

Неплохо.Что делать, если вы пишете свое приложение на SWT?Насколько «абстрактным» на самом деле является AWT в этом случае?Просто признайте это:этот совет просто побуждает вас писать код пользовательского интерфейса в вашей бизнес-логике.Какой замечательный принцип.В конце концов, прошло всего десять лет с тех пор, как мы определили эту практику как одно из худших дизайнерских решений, которые вы можете принять в проекте.

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

Когда мне представляют подобные идеи, мне нравится смотреть на библиотеки и фреймворки, которые я использую и которые мне нравится использовать.

Например, хотя некоторые с этим не согласятся, мне нравится стандартный API Java.Мне также нравится Spring Framework.Глядя на классы в этих библиотеках, вы заметите, что очень редко встречаются методы установки и получения, которые предназначены только для предоставления какой-либо внутренней переменной.Есть методы названный getX, но это не значит, что это геттер в обычном смысле этого слова.

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

Я не верю, что он говорит, что никогда не используйте get/set, а скорее, что использование get/set для поля не лучше, чем просто сделать поле общедоступным (например,общедоступная строка Имя vs.общедоступная строка Имя {get;набор;}).

Если используется get/set, это ограничивает сокрытие информации OO, что потенциально может заблокировать вас в плохом интерфейсе.

В приведенном выше примере Имя — это строка;что, если мы захотим позже изменить дизайн и добавить несколько имен?Интерфейс предоставляет только одну строку, поэтому мы не можем добавить больше, не нарушив существующую реализацию.

Однако, если вместо использования get/set у вас изначально был такой метод, как Add(имя строки), внутри вы могли обрабатывать имя отдельно или добавлять в список или что-то еще, а также вызывать метод Add извне столько раз, сколько вы хотите добавить. больше Имен.

Цель ОО — проектировать на определенном уровне абстракции;не раскрывайте больше деталей, чем вам абсолютно необходимо.

Скорее всего, если вы только что обернули примитивный тип методом get/set, вы нарушили этот принцип.

Конечно, это если вы верите в цели ООП;Я считаю, что большинство из них этого не делают, на самом деле они просто используют объекты как удобный способ группировки функционального кода.

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

Геттеры и сеттеры имеют смысл, когда они отражают какую-то связную идею.Например, в классе многоугольников координаты x и y заданных вершин имеют значение за пределами границы класса.Вероятно, имеет смысл иметь геттеры, и, вероятно, имеет смысл иметь сеттеры.В классе банковского счета баланс, вероятно, хранится как частная переменная и почти наверняка должен иметь метод получения.Если у него есть установщик, он должен иметь встроенное журналирование, чтобы сохранить возможность аудита.

Есть некоторые преимущества геттеров и сеттеров перед общедоступными переменными.Они обеспечивают некоторое разделение интерфейса и реализации.Просто потому, что точка имеет .getX() функция не означает, что должен быть x, поскольку .getX() и .setX() можно заставить нормально работать с радиальными координатами.Во-вторых, можно поддерживать инварианты классов, делая все необходимое, чтобы поддерживать согласованность класса внутри установщика.Во-вторых, можно иметь функции, которые срабатывают на наборе, например, ведение журнала баланса банковского счета.

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

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

Тот факт, что геттерами и сеттерами часто злоупотребляют, не означает, что они бесполезны.

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

Это нарушает инкапсуляцию, потому что когда вы вызываете метод get/set, вам сначала нужно знать имя (или иметь хорошее представление) поля, которое вы хотите изменить, а во-вторых, вам нужно знать его тип, например.ты не мог позвонить

setPositionX("some string");

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

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

public void tryPositionX(int x) throws InvalidParameterException{
    if (x >= 0)
        this.x = x;
    else
        throw new InvalidParameterException("Holy Negatives Batman!");
}

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

tryPositionXAndLog(int x) throws InvalidParameterException{
    tryPositionX(x);
    numChanges++;
}

ИМХО, необходимость в геттерах/сеттерах, чтобы что-то работало, часто является признаком плохого дизайна.Воспользуйтесь принципом «говори, не спрашивай» или заново подумай, почему объекту вообще необходимо отправлять данные о своем состоянии.Предоставляйте методы, которые изменяют поведение объекта, а не его состояние.Преимущества этого включают более простое обслуживание и повышенную расширяемость.

Вы также упоминаете MVC и говорите, что в этом случае модель не может нести ответственность за свое представление. Аллен Голуб приводит пример создания уровня абстракции с помощью класса «дайте мне JComponent, который представляет вашу личность». что, по его словам, «изолирует способ, которым личности представлены от остальной части системы». Я недостаточно опытен, чтобы прокомментировать, будет ли это сработать или нет, но на первый взгляд это звучит достойной идеей.

Публичные методы получения/установки плохи, если они предоставляют доступ к деталям реализации.Тем не менее, разумно предоставить доступ к свойствам объекта и использовать для этого геттеры/сеттеры.Например, если у Car есть свойство цвета, можно позволить клиентам «наблюдать» его с помощью метода получения.Если какому-то клиенту нужна возможность перекрасить машину, класс может предоставить сеттер (хотя «перекрасить» — более понятное имя).Важно не сообщать клиентам, как свойства хранятся в объектах, как они обслуживаются и т. д.

Ммммм... он никогда не слышал о концепции инкапсуляции.Методы Getter и Setter используются для управления доступом к членам класса.Сделав все поля общедоступными... любой мог записать в них любые значения, которые хотел, тем самым полностью сделав весь объект недействительным.

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

Инкапсуляция (информатика)

...и если они действительно злые, встроит ли .NET концепцию свойства в язык?(Методы Getter и Setter, которые выглядят немного красивее)

РЕДАКТИРОВАТЬ

В статье упоминается инкапсуляция:

"Геттеры и сеттеры могут быть полезны для переменных, которые вы хотите инкапсулировать, но вам не обязательно использовать их для всех переменных.На самом деле, использование их для всех переменных — это неприятный запах кода."

Использование этого метода в долгосрочной перспективе приведет к тому, что код будет чрезвычайно сложно поддерживать.Если в середине проекта, охватывающего годы, вы обнаружите, что поле необходимо инкапсулировать, вам придется обновить КАЖДУЮ ССЫЛКУ на это поле повсюду в вашем программном обеспечении, чтобы получить выгоду.Звучит намного разумнее использовать правильную инкапсуляцию заранее и избавить себя от головной боли позже.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top