Как инкапсулировать внутренние классы в API, написанном на Java?


9

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

Для структурирования я в настоящее время вижу два пути:

1. использовать пакеты.

плюсы: библиотека может быть аккуратно структурирована. Все на своем месте.

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

2. использовать статические внутренние классы, все в одном пакете.

плюсы: нужны только очень небольшие публичные вещи (классы, методы и т. д.).

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


Есть ли лучший способ получить маленький API в хорошо структурированной библиотеке?

Изменить: я забыл упомянуть: это для библиотеки Android. Поэтому нет java9.


Почему ваши внутренние классы должны быть статичными?
Дэвид Арно

Разве внутренние классы не делают единицы кода больше? Я имею в виду, что класс с несколькими внутренними классами может стать очень длинным.
Тулаинс Кордова

2
@ TulainsCórdova, хороший момент, я читал термин «внутренний» как «внутренний», который, я думаю, Java называет «пакетный приватный». Обычный способ создания библиотеки, безусловно, состоит в том, чтобы иметь один пакет, содержащий несколько открытых классов, а все остальное - внутренний / пакет-приватный.
Дэвид Арно

Привет @frmarkus. Я попытался переписать заголовок вашего вопроса, чтобы быть более конкретным и избежать «неясного, что вы спрашиваете», близких голосов Не стесняйтесь отредактировать его, если считаете, что оно искажает ваш фактический вопрос.
Андрес Ф.

1
@ TulainsCórdova: Да, кодовые единицы становятся большими (3 тыс. Строк кода на файл). Это еще одна важная проблема этого способа структурирования.
Маркус Фрауэнфельдер

Ответы:


1

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

Это очень умно. Остерегайтесь умных.

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

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

Кроме того, это будет работать. Это просто покажется странным.

Люди больше привыкли к тому, что внутренние классы используются как EntrySet в Hashtable. Он закрытый, поэтому я не могу его создать, но он реализует общедоступный интерфейс, поэтому я просто общаюсь с ним через интерфейс и что-то могу взять для меня.

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

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

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

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

Modifier        Class     Package   Subclass  World
public          Y         Y         Y         Y
protected       Y         Y         Y         N
no modifier     Y         Y         N         N
private         Y         N         N         N 

Что вы действительно хотите, так это доступ к модулю. Таким образом, вы можете хранить свои тесты в одном пакете и код в другом. К сожалению, у нас его нет на Java.

Большинство людей просто делают 1 и расширяют API. Правильное использование интерфейсов удерживает давление от реализации.

Взломать то, что вы хотите в 1, еще страшнее. Посмотрите на стек вызовов и сгенерируйте исключение всякий раз, когда вам позвонили из пакета, который вам не нравится. Eeew.


3

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

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

Вы можете сделать это буквально, определив весь API в терминах интерфейсов Java и предоставив некоторое количество фабричных классов для создания объектов реализации. Это то, что делает JDBC.

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


1
К сожалению, это полный ход. Это оставляет много публичных классов. Они могут иметь подсказки (быть фабриками или «внутренними»). Но я должен применить дополнительные инструменты к ним (ко всем публичным классам), это просто не хорошо.
Маркус Фрауэнфельдер

@frmarkus - я думаю, что (1) вы ожидаете слишком многого от контроля доступа, или (2) вам необходимо переосмыслить структуру вашего пакета, чтобы классы из одного пакета не зависели от классов из другого пакет (если вы можете хранить все как статические вложенные классы, это не должно быть сложным).
kdgregory
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.