Альтернатива защищенная упаковка в kotlin
В java у нас есть модификатор защищенных пакетов (по умолчанию) для классов, который позволяет иметь много классов в одном пакете, но отображать только несколько из них и сохранять логику инкапсулированной.
С kotlin, похоже, это не так, если я хочу иметь несколько других классов, которые должны быть видны друг другу, но не дальше, я должен использовать закрытый модификатор, который ограничивает видимость для одного файла... так что, по сути, если у вас было 10 классы в пакете, и только один из них был общедоступным, теперь у вас будет один огромный файл со всеми классами в нем (и private
повсюду)...
Это нормальная практика или есть способ достичь некоторой подобной модульности в kotlin?
Я не понимаю, имеют ли они понятие пакета, почему они избавились от защищенного доступа пакета...
Обновление: у нас может быть видимость, защищенная пакетами
смотрите обсуждение здесь
5 ответов
Kotlin, по сравнению с Java, в меньшей степени полагается на модель пакетов (например, структура каталогов не привязана к пакетам). Вместо этого Котлин предлагает internal
видимость, которая предназначена для модульной архитектуры проекта. Используя его, вы можете инкапсулировать часть вашего кода в отдельный модуль.
Таким образом, на объявлениях верхнего уровня вы можете использовать
private
ограничить видимость файлаinternal
ограничить видимость модуля
На данный момент нет другого варианта ограничения видимости.
Почти замена для частной видимости пакета доступна с использованием функции требований согласия (благодаря pdvrieze в обсуждениях Kotlin). Это синтаксис аннотаций, обычно используемый для пометки экспериментальных функций в API.
Чтобы использовать его, создайте аннотацию, обозначающую частные объявления пакета:
@RequiresOptIn(message = "Only to be used in MyPackage")
@Retention(AnnotationRetention.BINARY)
annotation class MyPackagePrivate
Затем аннотируйте любые методы, которые вы хотите сделать закрытыми для пакета:
@MyPackagePrivate
fun aPackagePrivateMethod() {
// do something private within a package
}
Таким образом, для любого метода, который вызывает аннотированный метод, будет сгенерировано предупреждение, если вызывающий метод сам не аннотирован соответствующим@OptIn
аннотация, здесь показано наclass
уровень:
@OptIn(MyPackagePrivate::class)
class AClassInThePackage {
fun userOfPackagePrivateMethod() {
aPackagePrivateMethod()
}
}
Таким образом, это производит аналогичный эффект для Java-пакета private, за исключением того, что вызывающие методы должны явно соглашаться на использование частного объявления пакета.
Если желательно сгенерировать ошибку, а не предупреждение,level
параметр@RequiresOptIn
можно указать:
@RequiresOptIn(level = RequiresOptIn.Level.ERROR, message = "Only to be used in MyPackage")
// annotation declaration as before
В качестве обходного пути для меня на Android я создал @PackagePrivate
аннотации и проверка ворса для управления доступом. Здесь вы можете найти проект.
Очевидно, что Lint-проверки не так строги, как проверки компилятора и некоторая настройка, необходимая для сбоя сборки при ошибках. Но студия Android автоматически проверяет наличие ворса и сразу же показывает ошибку при наборе текста. К сожалению, я не знаю, как исключить аннотированные элементы из автозаполнения.
Кроме того, поскольку lint - это инструмент, предназначенный исключительно для времени компиляции, проверки во время выполнения не выполняются.
Как указывает @hotkeys, вы можете использовать internal
Ключевое слово в модуле. Я обычно работаю с Eclipse и Maven, и для меня не практично создавать эти модули.
Может быть, для другого технического стека с IDEA или Gradle это более практично; Я не знаю, потому что я никогда не использовал их.
Другой вариант - поместить все классы пакета в один файл. Это не всегда практично или элегантно.
Для меня package
видимость чрезвычайно полезна для ее документирования. Я хочу знать, какой открытый интерфейс какой-либо пакет представляет для остальной части проекта. Я хочу скрыть фабричные реализации классов и так далее.
Поэтому, даже если в Java можно проложить свой путь к закрытым пакетам классам и методам, я все равно хотел бы использовать package
ключевое слово.
Что я сделал, так это создал проект с одной аннотацией:
package com.mycompany.libraries.kotlinannotations;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Documented
@Retention(SOURCE)
@Target({ TYPE, METHOD, CONSTRUCTOR })
/**
* Use in Kotlin code for documentation purposes.
*
* Whenever a Kotlin class or method is intended to be accesible at package level only.
*
*/
public @interface PackagePrivate {
}
Тогда я могу использовать эту аннотацию в любом проекте Kotlin.
Второй шаг, который я еще не обошел, и который я хотел бы сделать в какой-то момент, - это создание правила PMD, чтобы реализовать это с помощью maven (или любого другого инструмента для сборки в этом отношении), а также иметь возможность видеть Нарушения правил в моей IDE с плагином pmd.
На данный момент Kotlin еще не является одним из языков, поддерживаемых pmd (т.е. с собственным модулем). Но PMD находится в активной разработке, и популярность Kotlin растет, поэтому есть шанс, что он будет разработан в какой-то момент. Это просто моя лучшая догадка.
Защита пакетов в Kotlin бессмысленна, потому что у него «на самом деле» пакетов нет.
В Java пакет был привязан к структуре каталогов. Итак, если вы поместите свой класс в
Фактически, проект Kotlin отлично работает без ЛЮБЫХ объявлений пакетов. Это только подчеркивает, что пакеты - это « больше то, что вы бы назвали рекомендациями, чем действительные правила ». Это удобная функция, полезная только для того, чтобы не загромождать пространство имен, и не более того.