Альтернатива защищенная упаковка в 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 удаляет связи между каталогом и пакетом, поэтому я могу поместить свой класс в каталог, но объявить свой пакет как - и получите доступ ко всем свойствам, которые вы указали как частный пакет.

Фактически, проект Kotlin отлично работает без ЛЮБЫХ объявлений пакетов. Это только подчеркивает, что пакеты - это « больше то, что вы бы назвали рекомендациями, чем действительные правила ». Это удобная функция, полезная только для того, чтобы не загромождать пространство имен, и не более того.

Другие вопросы по тегам