Подтвердить что ты не робот

Защищенные поля Java vs public getters

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

(Получатель будет публичным независимо)

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

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

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

Ответ 3

Прямой доступ к полю не является предпочтительным. Используйте установщики public или protected и получатели.

Получателю не обязательно быть public - если вы хотите скрыть данные от "аутсайдеров", но дайте данные подклассам, используйте protected

Ответ 4

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

Ответ 5

Эффективное Java 2nd Edition говорит

Пункт 13: Минимизировать доступность классов и членов

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

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

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

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


Если вы знаете С++, вы, вероятно, знаете, что

const int * someMember

отличается от

int * const someMember

Последний как последний массив в java.


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

Ответ 6

Как правило, вы должны использовать рекомендации Sun. Существует одно большое исключение: если вы программируете для Android.

Причина - производительность. При каждом вызове виртуального метода возникают проблемы с использованием таблицы поиска для маршрутизации метода к его объекту. Эти служебные данные не задействованы при доступе к локальной переменной.

Вот несколько ссылок, которые объясняют это немного подробнее:

http://developer.android.com/training/articles/perf-tips.html#GettersSetters

http://blog.leocad.io/why-you-shouldnt-use-getters-and-setters-on-android/

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

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

В plain ol 'Java, getters и seters выполняют обе задачи. Но Android отличается. Если вы делаете # 1, вам следует использовать публичные геттеры и сеттеры. Если вы делаете # 2, вам следует использовать защищенные поля. Если вы используете оба варианта, используйте оба параметра.

Ответ 7

Доступ к защищенным полям из подкласса является одним из способов нарушения наследования инкапсуляции. По этой причине лучше использовать публичный API.

Ответ 8

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

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

Рассмотрим следующий абстрактный пример с автомобилем: - у вас есть базовый класс Car и производный класс Porshe. - У класса Car может быть поле типа engine, значение которого не устанавливается в конструкторе Cars (возможно, тип двигателя известен только после инициализации объекта) - Вы создаете объект класса Porshe, который содержит некоторую логику, используемую для вычисления типа двигателя с использованием некоторых внешних данных,

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

Да, некоторые люди, вероятно, скажут: "Тогда используйте защищенный сеттер!". И еще раз повторюсь: на языках ООП мы работаем с объектами, а не с классами Принцип единой ответственности - да, но как объект, а не как класс. Если вы скажете: "в какой-то момент, если мы используем защищенные поля с 3 или 5 уровнями наследования, может быть сложно понять, что происходит с полем, если каждый класс выполняет с ним какую-либо операцию". И тогда я отвечаю: это еще один антипаттерн - ваш объект, вероятно, слишком велик на данный момент и лишается принципа единой ответственности.