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

Какая польза от защиты уровня пакета в java?

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

Существуют ли какие-либо законные варианты использования в реальном мире?

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

4b9b3361

Ответ 1

Есть два хороших применения для видимости уровня пакета (по моему опыту):

1) Определение "внутренних" классов в публичном API. Обычно вы определяете свои интерфейсы и основные заводы как общедоступные и "внутренние" реализации как уровень пакета. Затем публичные заводы могут создавать классы реализации уровня пакета и возвращать их как экземпляры открытых интерфейсов. Это позволяет пользователям получать доступ только к тому материалу, который им нужен.

Недостатком является то, что вы должны иметь все это в одном пакете, что почти никогда не является хорошей идеей для любого разумного размера API. JSR 294/modules/Проект Jigsaw в Java 7, будем надеяться предоставить альтернативу, указав новый модификатор видимости (module), который можно использовать для доступа к классам внутри модуля через пакеты, не делая их видимыми вне модуля. Вы можете найти пример того, как это будет работать в этой статье.

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

Ответ 2

Вы говорите о приватной защите пакетов в Java? Это защита, которая по умолчанию действует для членов класса. Это полезно иногда, если у вас есть классы, которые тесно взаимодействуют таким образом, что требуется дополнительная информация или методы для видимости.

Скажем, у вас есть класс Sink, и к нему могут писать несколько классов. У Sink есть общедоступный метод, который принимает базовые типы данных и частный метод пакета, который принимает исходные байтовые массивы. Вы не хотите, чтобы этот метод был общедоступным, потому что вы считаете его слишком низкоуровневым для своих пользователей, но вы хотите, чтобы ваши другие классы (в пакете Sink) записывались в этот Sink, используйте его. Таким образом, вы принимаете метод, принимающий байтовый массив массива private, и классы вашего пакета, такие как ByteStreamSource, могут его использовать. Теперь ваша защита выглядит так:

     User   Code using the package   User
------ | -----------------------------|----- package public Interface
       |                              |
    Sink <-   package priv. iface  -> Sources

Внутренний интерфейс пакета ортогонален публичному интерфейсу, установленному общедоступными методами. Пакет private'ness увеличивает инкапсуляцию, потому что это побуждает вас не публиковать то, что не должно быть публичным. Он похож на ключевое слово friend в С++ и ключевое слово internal в С#.

Ответ 3

Он может использоваться для классов реализации, с одной стороны. Например, EnumSet является абстрактным классом, и никакие классы реализации не показаны в документах. Зачем? Потому что есть два класса реализации: один для перечислений с 64 или менее элементами и один для 65 или более - и вам действительно не нужно знать, какой из них вы используете. На самом деле вам даже не нужно знать, что существует более одной реализации. На самом деле вам даже не нужно знать, что EnumSet является абстрактным - вам просто нужно знать, что вы можете вызвать один из статических методов и вернуть обратно Set.

В этом случае частные внутренние классы могли бы быть достаточными (хотя и громоздкими, особенно для больших классов). Но иногда другим классам в пакете нужен доступ к таким деталям реализации. protected может работать, но тогда они также будут открыты для подклассов.

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

Ответ 4

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

Например, многие из моих проектов работают с общедоступными интерфейсами и "скрытыми" классами, которые их реализуют. Пользователи используют заводы и получают ссылку на интерфейс, который соответствует "скрытой" конкретной реализации. С защитой пакетов я теоретически мог бы только разоблачить интерфейсы и factory.

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

Ответ 5

Претензия по умолчанию, то есть защита "пакета" означает, что она является частной для пакета, но может "видеть" все, что не является приватным для класса в пакете. Одно использование - для вспомогательных классов для пакета; скажем, у вас есть класс, который управляет объединенным ресурсом, который вы не хотите делать видимым, вы можете поместить его в класс защиты по умолчанию. Теперь он может использоваться всем в пакете и может иметь доступ к любым защищенным внутренним элементам других классов, но он не является частью видимого пакета для пользователя.

Ответ 6

Другое использование защиты по умолчанию в Java - это производительность.

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

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

Ответ 7

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

Однако классы пакета-private полезны. Возможно, вы захотите предоставить реализацию интерфейса, используя класс private-package. Метод factory может быть объявлен для возврата объекта, реализующего данный интерфейс. В этой ситуации не важно знать, какой класс предоставляет реализацию для интерфейса. Сделав класс package-private, он не является частью публичного API и поэтому может быть изменен или заменен в будущих версиях.

В Oak, языке, который позже стал Java, было только 3 уровня доступа.

Если бы я перепроектировал Java сейчас, я бы избавился от текущего по умолчанию (package-private) и сделал закрытым по умолчанию. Частный класс будет являться частным в пределах его охватывающей области (пакета), которая будет работать точно так же, как классы пакета-private уже работают и более совместимы с использованием 'private' для членов.

Ответ 8

Причина, по которой никто не использует доступ к уровню пакета, вероятно, является психологическим эффектом. Каждое введение в Java проповедует инкапсуляцию, которая понимается как объявление всех полей private. Частный доступ очень часто слишком узкий, поэтому необходимо добавить публичный геттер/сеттер. Этот шаблон затем повторяется во всей кодовой базе: частные поля и общедоступные методы повсюду. По иронии судьбы, инкапсуляция шаблонов подстановки, так как вся реализация по существу прибита парными геттерами/сеттерами.

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

Суперпакеты в 1.7 могут изменить правила игры.

Ответ 9

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

По-моему, это основной механизм защиты, и иерархия защиты будет хорошей функцией.

Ответ 10

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

Аналогия может быть методом "друга" в С++.

Ответ 11

Я знаю ветеранов Java 5-10 + лет, которые не понимают, что protected подразумевает закрытие пакета private. Это одно для меня, делает пакет частным ужасающим языком. Лично я не думаю, что есть какая-то оправданная причина использовать приватный пакет в любом случае. Рассмотрим варианты использования:

  • Пакет частных классов: используйте внутренние классы. Еще один плакат предположил, что существует небольшое (небольшое) ограничение производительности для внутренних классов против пакетов частных классов, но для меня это не является хорошей причиной плохого дизайна. Пакет частных и внутренних классов, которые я считаю деталями реализации, и, как таковые, я считаю, что лучше "скрыть" их как внутренние классы;
  • Пакет личных данных: я не вижу причин для них; и
  • Пакет приватных методов: это в значительной степени эквивалент методов друзей С++. У друзей С++ был один хороший raison d'etre, и это было для экстернализации перегрузки оператора вне класса, что позволило первому аргументу быть чем-то другим, кроме самого класса. В Java нет такого прецедента, который просто прекращает выполнение инкапсуляции и абстракции.

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

И нет абсолютно никакого способа предотвратить это.

С# имеет лучшую систему доступа в том, что защищенный не подразумевает внутренний доступ. Но я считаю это - наряду с изменчивым классом Date - очень большими недостатками.

Ответ 12

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

Ответ 13

В настоящее время я обсуждаю многие из этих проблем, и это хорошая дискуссия. Я предпочитаю делать все частные вещи такими, какими они должны быть, но тогда я пишу тонну отражения в unit test частном программном коде. Это, я думаю, чистый OO способ сделать это. Тем не менее, я обнаружил, что можно закрепить файл jar, чтобы область пакета была ограничена внутри модуля (jar). Это, на мой взгляд, делает область упаковки более приемлемой. Возможно, я захочу сломать хорошую инкапсуляцию в обмен на сокращение моего кода unit test на долю того, что он будет. Мысль заключалась в том, что если кто-то работал в одной и той же библиотеке и в том же пакете, что они были бы достаточно интимными с базой кода, чтобы не получить доступ к членам области видимости пакета вне класса без разумной дискуссии по дизайну. Это по-прежнему непростой вызов. Было бы неплохо иметь тип класса класса friend для этого типа экземпляра, чтобы мой кодовый код unit test получал доступ к моему личному коду, но не был доступен другим классам. Я только что запечатал файлы jar в этом проекте через maven:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.3.2</version>
            <configuration>
                <archive>
                    <index>true</index>
                    <manifest>
                        <addClasspath>true</addClasspath>
                    </manifest>
                    <manifestEntries>
                        <sealed>true</sealed>
                    </manifestEntries>
                </archive>
            </configuration>
        </plugin>

Теперь я обсуждаю, как вытащить кучу кода отражения во время модульных тестов.

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

Ответ 14

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

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

Защита пакетов позволяет вам экспортировать только несколько классов из вашего пакета, сохраняя конфиденциальность остальных.

В теории это отличная идея, на практике вы почти никогда ее не видите.

Ответ 15

"Я знаю, как защита уровня пакета в java работает... и никто, кажется, не использует его".

Что они используют?

Объявляют ли они все свои классы?

Принцип бремена принимает две формы.

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

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

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

Бремя создания или изменения любой программной системы зависит от количества созданных или модифицированных программных единиц.

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

Максимальное потенциальное бремя, которое может наложить модифицированный программный блок, - это воздействие всех программных единиц, которые зависят от него.

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

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

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

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

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

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

Звучит... странно.