【问题标题】:Package protected alternative in KotlinKotlin 中的包保护替代方案
【发布时间】:2016-06-25 03:44:52
【问题描述】:

在 Java 中,我们为类提供了 package protected(默认)修饰符,它允许我们在一个包中拥有多个类,但只公开少数几个类并保持逻辑封装。

对于 Kotlin,情况似乎并非如此。如果我想让一些类彼此可见但不再可见,我必须使用私有修饰符来限制对单个文件的可见性。

因此,如果您希望一个包中有 10 个类,但只有其中一个是公开的,那么您必须拥有一个包含所有类的大文件(并且到处都是 private)。

这是正常的做法还是有办法在 Kotlin 中实现一些类似的模块化?

我不明白:如果他们有包的概念,为什么他们要摆脱包保护访问?

更新:毕竟我们可能拥有包保护的可见性
see the discussion here

更新:如果您阅读讨论后仍然认为这是该语言的必备功能,请投票here

【问题讨论】:

  • 更多讨论链接:discuss.kotlinlang.org/t/…
  • 有一个包私有可见性或等效项的功能请求:KT-29227
  • Kotlin 提供internal
  • internal 是非常不同的事情,如果我使用 internal 来替换包可见性 id 有 200 个模块

标签: visibility kotlin


【解决方案1】:

与 Java 相比,Kotlin 似乎在较小程度上依赖包模型(例如,目录结构不绑定到包)。相反,Kotlin 提供了internal visibility,它专为模块化项目架构而设计。使用它,您可以将部分代码封装在单独的module 中。

因此,您可以在顶级声明中使用

  • private 限制对文件的可见性
  • internal 限制对模块的可见性

此时,没有其他可见性限制选项。

【讨论】:

  • 嗯,我喜欢内部的,但我们会在 java9 中更好地修复它但是我从未见过有人会创建相同的包只是为了使用代码......毕竟如果有人这么多决心违反模块化,如有必要,他只会复制粘贴代码……我在这里关心的是可用性。因为简单地将大量代码放在一个文件中是愚蠢的......
  • 好的,但是现在我正在将一个 java 项目迁移到 kotlin,并且我强制执行了非常好的可见性,通常这些是一些由 4-5 个类组成的实用程序,其中只有一个对外面的世界……现在有了 kotlin,除非我将所有内容都放在同一个文件中,否则我无法选择拥有相同的可见性……我理解正确还是有其他我不知道的方法?
  • @JaysonMinard 我同意小班授课。但是,假设您的 Java 包由 5 个类组成,每个类 200 行,突然间为了模仿 Kotlin 中的相同可见性,您必须创建一个 1000 行长的文件。这就是我在上面所说的有争议的。
  • 包级别的可见性在 Java 中很酷。即使它可以被“黑客攻击”,您也不必这样做。它使受保护内容的单元测试变得容易且分离良好。 Java 中的“受保护”可见性也增加了可读性,它表示您不能直接使用该成员,除非您是包维护者。仅仅为了正确的可见性问题将一个项目分解成更多的项目/模块是没有意义的,只是烦人的额外工作。所以在这个问题上,Java 还是比 Kotlin 好。
  • “Java 的包保护可见性的主要缺陷是每个人仍然可以访问您的代码”——如果你问我,这是一个相当糟糕的理由。无论如何,您都可以使用反射来访问您想要的任何内容。访问修饰符不是为了安全,它们是为了防止意外错误和指定 API 合约。如果有人在同一个包中编写代码,可以肯定地认为这不是意外,他必须知道自己在做什么。如果您想要安全,请使用SecurityManager
【解决方案2】:

作为我在 android 上的解决方法,我创建了 @PackagePrivate 注释和 lint 检查来控制访问。 Here你可以找到项目。

Lint 检查显然不像编译器检查那么严格,并且需要一些设置才能使构建失败。但是 android studio 会自动进行 lint 检查,并在输入时立即显示错误。不幸的是,我不知道如何从自动完成功能中排除带注释的成员。

此外,由于 lint 是一个纯粹的编译时工具,因此不会在运行时进行检查。

【讨论】:

  • 它实际上是针对 android 的吗? kotlin 不仅仅是 android,如果可能的话,拥有通用库会很棒
  • 不幸的是,它是特定于 android 的,原因是使用了 Android Lint。 Android Studio 很好地支持它并即时运行检查,立即在 IDE 本身中显示错误。可能可以使用ktlint 之类的东西来实现这些检查,但是如果没有 IDE 支持,用户体验对于这种检查来说真的很糟糕。
  • 提示:您可以使它更像一个关键字,并通过在每个包上添加类型别名来避免在每个文件中导入它,例如:internal typealias pkg = io.github.esentsov.PackagePrivate; internal typealias private = io.github.esentsov.FilePrivate。并像@pkg val ... @private internal val ... 一样使用它
  • 你应该查看android的@hide注释以排除在自动完成中。
【解决方案3】:

正如@hotkeys 指出的那样,您可以在module 中使用internal 关键字,或者您可以将原本属于一个包中的所有类放在一个文件中,但是在一个文件中粘贴多个类可能是有问题的设计决定。

对我来说,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 插件。

pmdat this moment 中没有完整的 Kotlin 支持,但在某些时候似乎是可以预料的。

【讨论】:

    【解决方案4】:

    基于包的保护在 Kotlin 中毫无意义,因为包本身不受保护

    在 Java 中,包与目录结构相关联。因此,如果您将您的课程放在com\example\yoursecretengine 中,那么任何(故意或意外)添加流氓课程的尝试都会很容易引起注意。这就是我们所依赖的安全性。

    Kotlin 消除了目录和包之间的联系,因此我可以将我的类放在“我的”目录中(例如src\java\pl\agent_l\illegalaccess),同时将其包声明为com.example.yoursecretengine - 并获得对您所指的所有属性的访问权限作为包私有。

    事实上,Kotlin 项目无需任何包声明即可完美运行。这只是强调软件包“您称之为指南而不是实际规则”。它们是一种便利功能,仅对整理命名空间有用,仅此而已。

    相关quotes from kotlinlang

    与许多其他语言不同,Kotlin 包不需要文件具有任何特定位置 w.r.t。本身;文件与其包之间的连接仅通过包头建立。

    还有:

    文件中没有包头意味着它属于特殊的根包。

    【讨论】:

    • 请看this
    • @mightyWOZ 谢谢,我已经包含了你的链接。你现在觉得怎么样?
    • 没有人将包可见性用于任何类型的安全性我厌倦了这个论点,它关于以一种很好的方式打包你的代码,它将相关的东西放在一个文件中很糟糕,就像 kotlin 一样紧凑很糟糕,就这么简单
    • 如果你在做任何非 hello world 项目,他们会强迫你要么把所有东西都放在一个文件中,要么污染公共命名空间,我敢打赌你会做一个或另一个
    • 没关系,我一直在争论这个我已经厌倦了,我不知道人们是如何使用它的,对我来说,包可见性是一种将组件分成多个类的方法,并且只暴露了其中一个,因为它不在 kotlin 中
    猜你喜欢
    • 2010-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-31
    • 2019-11-15
    • 2019-03-31
    相关资源
    最近更新 更多