Прежде всего, давайте рассмотрим почему . Почему вы ищете это? Вы ищете способ запретить потребителю вызывать нежелательные методы в базовом классе.
Если вы думаете, что ищете что-то еще, подумайте еще раз.Если вы просто хотите скрыть это, подумайте еще раз.Конечный пользователь вообще не будет заботиться о деталях реализации.
Если вы создали базовый класс, то не публикует API, который в первую очередь разрешает этот .Об этом специально была глава в Чистый код .
Если ваш базовый класс расширяет другой базовый класс, у вас проблемы. Вы не можете скрыть уже опубликованный API , если вы расширяете и не инкапсулируете.
Я хочу, чтобы этот класс был ТОЛЬКО доступен для получения подкласса, но не доступен какзависимость.Есть ли способ выполнить такое ограничение в Java?Может быть, в Котлине это было бы возможно?
Нет.Это не мнение, это намеренно.
Может быть сложный способ скрыть методы родительских классов, но не в классе, с которым потребитель взаимодействует (расширяет).
У вас может быть несколько слоев базовых классов, каждый из которых находится в своем собственном модуле Gradle, и вы можете установить implementation
зависимость типа, но затем, если вы можете расширить класс, если вы его видите, обратитесь к нему, вы также можете использовать его где угодно.
Представьте себе:
- потребительский модуль ->
ConsumerActivity
extends ExtensibleActivity
- ваш библиотечный модуль ->
ExtensibleActivity
extends BaseActivity
- Ваш базовый библиотечный модуль ->
BaseActivity
extends Activity
- Android SDK ->
Activity
Модуль потребителя видит только то, что находится внутри «вашего библиотечного модуля».Он знает о ExtensibleActivity
, но не может видеть ни один из его супертипов.Потребитель все еще может ссылаться на ExtensibleActivity
и его методы.Побочный эффект заключается в том, что суперклассы не известны с точки зрения потребителя, вы не можете передать экземпляр ExtensibleActivity
как Activity
, потому что система типов не знает, что он расширяет Activity
, потому что он не видит промежуточный тип BaseActivity
.Вот график того, что видит потребитель:
ConsumerActivity -> ExtensibleActivity -> BaseActivity (doesn't exist) -> ??? (don't know)
В этот момент вы просто должны спросить себя: «Это должно было быть расширено Activity
во-первых?».
Этопросто ужасно работать сМного потраченных впустую усилий на то, о чем вам не нужно беспокоиться.
Если вы хотите что-то скрыть, используйте композиция вместо наследования .Поместите свою логику в Fragment
или, что еще лучше, поместите свою логику в пользовательский компонент с поддержкой жизненного цикла .Таким образом, вы в общей сложности контролируете API .Сделайте так, чтобы вам не пришлось беспокоиться о том, откуда он вызывается.
Напишите хорошую документацию для вашего кода и руководство по использованию .
И, пожалуйста, позвольте мне разбить вашу чертову библиотеку, если я решу использовать ее неправильно.
У вас есть несколько методов в вашем API?Большой!Никто не помешает мне вызвать их из строя.Вы можете написать в своем руководстве, как это должно использоваться, но в конечном итоге я пишу свою программу, используя вашу библиотеку, и если я делаю это неправильно, то это моя вина, когда она ломается.Это хорошо.