Рубрики
Без рубрики

Вступающий в силу Java Вторник! Сведите к минимуму доступность классов и участников

Погружение в пятнадцатую главу Эффективной Java. Помеченный как java, эффективный, инкапсуляция, архитектура.

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

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

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

Для переменных-членов/функций у нас есть еще несколько вариантов (от наиболее доступных до наименее доступных):

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

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

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

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

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

Наконец, мы подходим к тому, что новые функции JVM дают нам для контроля нашей доступности, то есть модульной системы. Модульная система Java позволяет модулю (в основном jar) определять, какие пакеты он будет экспортировать за пределы себя. Таким образом, потребителю этого модуля будет разрешен доступ только к общедоступным и защищенным компонентам в экспортированных пакетах. Это неявно создает в основном два новых уровня доступа, которые не экспортируются общедоступны и защищенные компоненты, которые могут использоваться в кросс-пакете внутри модуля, но не за его пределами. Это в чем-то похоже на уровень доступа Kotlin внутренний .

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

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

Оригинал: “https://dev.to/kylec32/effective-java-tuesday-minimize-the-accessibility-of-classes-and-member-2m50”