Ява защищенные поля против публичных геттеров


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

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

7 54

7 ответов:

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

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

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

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

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

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

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

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

геттер не должен быть public - Если вы хотите скрыть данные от "посторонних", но передать данные в подклассы, используйте protected

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

эффективное Java 2-е издание говорит

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

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

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

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

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


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

const int * someMember

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

int * const someMember

последний похож на окончательный массив в java.


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

Как правило, вы должны использовать рекомендации 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/

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

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

в простой Ol ' Java, геттеры и сеттеры выполняют обе задачи. Но Android-это другое. Если вы делаете #1, то вы должны использовать публичные геттеры и сеттеры. Если вы делаете #2, то вы должны использовать защищенные поля. Если вы делаете оба, используйте оба.

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