在Java中定义公共库接口

4
有哪些选项可以定义Java库的公共接口?
例如,我经常发现某些内容是公共的,因为库中的另一个包需要它们(尽管仍然具有共同的基本包,例如com.stackoverflow.mylib),所以它们不能具有包访问级别,通常人们不想要大型包(似乎使用Spring的人坚持使用单独的控制器/服务/模型/impl等包,导致一个“功能”被强制跨越许多包,而给定的服务可能是完全的内部实现细节,不适用于外部使用...)。
因此,理想的目标是使我提供给第三方的Jar清楚地表明这些内容不应该被使用,最好根本不提供它们(在API jar中不存在),这样他们就无法使用和编译那些内部对象/方法。
更理想的情况是,只有从某种工厂(例如提供的Spring Bean)获得对象的方式,才能防止直接从其代码或自定义bean进行实例化(可能会在升级后留下一些未初始化的属性)。
我目前知道的两种正式方式是:
在一些我参与的项目中,有一个api包(例如com.stackoverflow.mylib.api),规则是只有该包的内容可以被外部用户直接访问。
在我参与的其他一些项目中,有一些自定义属性,例如@PublicSDK,用于标记供公众使用的对象和方法(我认为还需要一些额外的内容来确保只有被标记为这样的内容才包含在公开分发的javadoc和api jar中)。

1
请留下评论或进行/建议编辑,不要只是关闭投票...我想知道给定情况(库代码)的技术选项是什么(即列出任何相关的优点和缺点)。 - Fire Lancer
1个回答

1
首先要问自己的是 - 你真的需要隐藏实现细节吗
我这么说的原因是,这样做会有一些费用,具体取决于您的情况,可能值得支付,也可能不值得。
例如,如果您的API被团队外的开发人员使用,则可能值得支付费用;但是,如果只是为了在团队内部隐藏实现细节,我认为这是过度的。
如果API仅供项目内部使用,则尝试仅依赖于抽象类型或接口的标准就足够了(已经是标准)。
但是,假设您确实需要隐藏实现并仅公开API,则我知道的最好方法是生成两个jar文件 - 一个包含公共API,另一个是该API的实现。
如果您正在使用Maven或Gradle构建使用您的API的项目,则只需声明对API jar(artifact)的编译时依赖项和对实现jar(artifact)的运行时依赖项即可。
这种模式可以在常见的Java API中看到,最新的例子是JSON API,它作为Glassfish的一部分单独实现。

根据我的经验,对于常见的模块,如果要提供给其他几个团队(或公众),通常人们会按照IDE所说的编码,IDE有文档(他们可能并没有真正阅读),并将其显示为公共的(因此他们也不会收到编译警告/错误)。然后,他们拒绝/没有资源来更改它,因此被迫支持这个内部事物的行为(因为该jar文件需要向后兼容到相当大的程度,以避免在客户服务器上出现困难的升级情况)... - Fire Lancer
那么这两个 jar 是如何生成的呢?这听起来很像我的第二种方法(使用属性从 API jar 中剥离某些内容)。 - Fire Lancer
简单来说,有两个项目 - 一个用于生成公共API,另一个用于生成实现。如果您正在使用Maven,请避免使用多模块pom的诱惑 - 这将使您在每次发布实现时都必须发布公共API,这在仅需要进行实现错误修复发布时会很麻烦。 - Nick Holt
更像选项1吗?有一组API类,它们提供了对实现类的薄包装? - Fire Lancer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接