5

我想对 API 用户隐藏服务(接口)的实现(具体类)。该实现由使用 Java API ServiceLoader机制的工厂提供给用户。此 Loader 要求实现类具有公共可见性。只要实现隐藏在用户不直接依赖的不同 JAR(API JAR 除外)中,就可以了。

但是,为了便于分发,具有默认实现的 JAR 的内容被打包到 API JAR 中。因此,用户有效地依赖于这个预打包的 JAR,其中默认实现类可用于公共可见性。没有什么能阻止人们直接实例化实现。我不希望这成为可能。

我的坏主意:

  • 实现一个自己的 ServiceLoader 版本,它允许加载包私有实现(顺便说一句,为什么 Java API ServiceLoader 不允许这样做?)
  • 提供单独的 API 和实现 JAR

您认为正确的方法是什么?有什么妥协吗?

使用 OSGi 或其他重型机器是不可能的。

4

4 回答 4

3

也许令人失望,但是:

  • 制作一个单独的罐子并将其与其他第三方罐子放在一起。
  • 让安装程序/部署过程处理所有的漂亮打包。
  • 不要在编译期间使这个 jar 可用;行家:<scope>runtime</scope>

唯一的另一种方法是@Deprecatedjavadoc 中的 have,作为注释如何使用 java 服务 API 使用相应的类。

于 2013-05-08T12:24:52.247 回答
1

在 C# 中,您可以创建一个仅对相关友程序集可见的内部接口,然后显式实现该接口。我不确定您将如何在 Java 中执行此操作,但从概念上讲,这就是我能够在 .NET 世界中解决此问题的方式。

编辑我只是查了一下,据我所知Java没有明确的接口实现。作为仅供参考,接口的显式实现要求您通过接口成员进行函数调用,您不能将其作为实现类的成员调用。这就是为什么我的技术对我有用的原因,至少在 .NET 世界中是这样。

或者,我建议将接口放在另一个 JAR 中,不要与 API 一起分发

于 2013-05-08T13:28:42.650 回答
0

您不能轻易阻止人们实例化/访问任何已发布的类。

因此,我可能会简单地包装ServiceLoader您正在使用的机制并提供通过 Java 接口引用的实例化类(而不是作为具体的实现引用)。

于 2013-05-08T10:01:13.477 回答
0

我更喜欢您的第一种方法,将实现类包设为私有,并使用 ServiceLoctor 检索特定服务。在我的项目中,包结构是这样的:

-package
   |-ServiceInterface(public)
   |-ServiceImplementation(default,package private)
   |-ServiceLocator(public)

服务定位器是这样的:

public class ServiceLocator{
    private static final Map<String,Service> services;

    static {
         services=new HashMap<String,Service>();
         services.put("default",new ServiceImplementation());//hide implementation
    }
    public Service getService(String name){
         return services.get(name);
    } 

    public registerService(Service service, String name){
         services.put(name,service)
    }
}

最终用户无权访问实现类,并且在以后,您可以轻松更改为使用不同的实现类。

于 2013-05-08T12:45:40.473 回答