解决缺少包访问说明符的方法?

时间:2012-03-08 00:49:45

标签: java jar packages encapsulation class-visibility

我是Java的新手。我发现,在尝试构建我的代码时,Java将源文件组织(目录结构)与包结构和包结构紧密地联系到类的外部可见性(一个类对所有其他包可见,或者没有)。 / p>

这使我很难将公共库的内部实现细节组织成相关功能的逻辑单元,同时保持良好的封装。 JSR 294解释得最好:

  

今天,可以将实现划分为多个包。   这种实现的子部分需要更紧密地耦合   彼此不同于周围的软件环境。今天   设计师被迫宣布该计划的元素   实施的其他子部分需要公共 - 从而   使它们在全球范围内可访问,这显然不是最理想的。

     

或者,整个实现可以放在一个单独的实现中   包。这解决了上面的问题,但是很笨拙,而且暴露了   所有子部分的所有内部结构。

所以我的问题是,这种限制存在哪些变通方法,以及什么是优点和缺点。利弊? JSR中提到了两个 - 使用包进行逻辑分组(违反封装);把所有东西放在一个包里(笨重)。这些变通办法还有其他优点/缺点吗?还有其他解决方案吗? (我已经模糊地意识到OSGi捆绑包,但我发现很难理解它们是如何工作的以及优点/缺点可能是什么(也许这是一个骗局)。似乎是与香草包相比,对于开发和部署而言非常具有侵入性。

注意:我会提供任何好的答案,但最佳答案将是在专业人士和答案中全面折叠的答案。其他人的弊端(抄袭!)。

相关(但不重复!)问题

预计“可能重复”的声音,这里是我在SO上发现的类似的问题;我在这里介绍它们以供参考,并解释为什么它们不回答我的问题。

3 个答案:

答案 0 :(得分:0)

ProGuard之类的工具可用于重新打包JAR,只展示您在配置文件中指定的那些类。 (除了优化,内联和混淆之外,它还可以执行此操作。)您可以在例如中设置ProGuard。 Maven或Ant构建,因此您将库公开方法编写为公共方法,然后使用ProGuard将其从生成的JAR中删除。

答案 1 :(得分:0)

我会让球滚动。窃取这个答案并添加/纠正/请详细说明!

将多个包用于多个逻辑分组

优点:相关代码的有效逻辑分组。

缺点:当不同包中的内部实现详细信息类需要相互使用时,必须将它们公开 - 甚至是最终用户 - 违反封装。 (通过对包含内部实现细节(如.internal或.impl)的包使用标准命名约定来解决此问题。)

将所有内容放在一个包中

优点:有效封装

缺点:如果库包含很多类,那么它对于库的开发/维护是不实用的

使用OSGi包

优点 :? (他们解决了这个问题吗?)

缺点:与仅部署.jar文件相比,在开发(对于库用户和作者)和部署方面似乎非常具有侵入性。

在Java 8中等待Jigsaw

http://openjdk.java.net/projects/jigsaw/

优点:解决问题的好处?

缺点:尚不存在,不知道具体的发布日期。

答案 2 :(得分:0)

我从未发现这是一个问题。解决方法(如果你想称之为)称为良好的API设计

如果您的图书馆设计得很好,那么您几乎总能做到以下几点:

  • 将主公共API放在一个包中,例如“my.package.core”或只是“my.package”
  • 将帮助程序模块放在其他程序包中(根据逻辑分组),但为每个程序包提供自己的公共API子集(例如工厂类,如“my.package.foobarimpl.FoobarFactory”)
  • 主公共API包仅使用辅助模块的公共API
  • 您的测试也应该主要针对公共API运行(因为这是您在回归或功能方面所关心的)

因此,对于我来说,包的“正确级别的封装”是为了暴露足够的公共API,使您的包可以有效地用作依赖。不多也不少。它是否被同一个库中的另一个包或外部用户使用并不重要。如果围绕这个原则设计包装,就会增加有效重复使用的机会。

只要您的API设计合理,使一部分软件包“全局可访问”真的不会造成任何伤害。请记住,包不是对象实例,因此封装并不重要:将包的元素公开通常 比暴露类的内部实现细节(我是同意应该几乎总是私密/受保护)。

例如考虑java.lang.String。它有一个很大的公共API,但无论你使用公共API做什么都不能干扰java.lang.String的其他用户。从多个地方同时使用作为依赖关系是完全安全的。另一方面,如果你允许java.lang.String的用户直接访问内部字符数组(这将允许不可变字符串的就地变异......讨厌!!),所有地狱都会破裂。

P.S。值得一提的是OSGi,因为它是一种非常棒的技术,在许多情况下非常有用。然而,它的最佳点在于模块的部署和生命周期管理(停止/启动/加载等)。代码组织恕我直言,你真的不需要它。