隐藏服务实现的最佳实践

时间:2013-05-08 09:57:37

标签: java design-patterns

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

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

我的坏主意:

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

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

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

4 个答案:

答案 0 :(得分:2)

令人失望但是:

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

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

答案 1 :(得分:1)

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

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

或者,我建议将接口放在另一个JAR中,而不是用API分发它

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

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

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

serviceLocator是这样的:

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)
    }
}

最终用户无权访问实现类,稍后您可以轻松更改为使用其他实现类。