Java 隐藏服务实现的最佳实践

Java 隐藏服务实现的最佳实践,java,design-patterns,Java,Design Patterns,我想对API用户隐藏服务(接口)的实现(具体类)。该实现由一个使用JavaAPI ServiceLoader机制的工厂提供给用户。此加载程序要求实现类具有公共可见性。只要实现隐藏在用户不直接依赖的另一个JAR(除了API JAR)中,这是可以的 但是,为了便于分发,带有默认实现的JAR的内容被打包到API JAR中。因此,用户有效地依赖于这个预先打包的JAR,其中默认的实现类是公开的。没有什么能阻止人们直接实例化实现。我不希望这成为可能 我的坏主意: 实现自己版本的ServiceLoader,

我想对API用户隐藏服务(接口)的实现(具体类)。该实现由一个使用JavaAPI ServiceLoader机制的工厂提供给用户。此加载程序要求实现类具有公共可见性。只要实现隐藏在用户不直接依赖的另一个JAR(除了API JAR)中,这是可以的

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

我的坏主意:

  • 实现自己版本的ServiceLoader,它允许加载包私有实现(顺便说一句,为什么JavaAPI ServiceLoader不允许这样做?)
  • 提供单独的API和实现JAR
你认为什么是正确的方法?有什么妥协吗


使用OSGi或其他重型机器是毫无疑问的。

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


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

但是:

  • 制作一个单独的罐子,并将其与其他第三方罐子放在一起
  • 让安装程序/部署过程处理所有组件的良好打包
  • 不要在编译时使用这个jar;maven:
    运行时

唯一的其他方法是javadoc中的have
@Deprecated
,以及如何使用java服务API使用相应类的注释。

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

-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)
    }
}
serviceLocator如下所示:

-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)
    }
}
公共类ServiceLocator{
私有静态最终地图服务;
静止的{
services=newhashmap();
services.put(“默认”,newServiceImplementation());//隐藏实现
}
公共服务getService(字符串名称){
return services.get(名称);
} 
公共注册服务(服务,字符串名称){
services.put(名称、服务)
}
}
最终用户没有访问实现类的权限,在以后的时间里,您可以轻松地更改为使用不同的实现类。

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

EDIT我只是查了一下,从中可以看出Java没有接口的显式实现。仅供参考,接口的显式实现要求您通过接口成员进行函数调用,您不能将其作为实现类的成员进行调用。这就是为什么我的技术对我有效,至少在.NET世界是如此


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

OK hide可能是个错误的词。我知道,有了反思,你可以做所有肮脏的把戏。当然,API只引用接口而不是实现。但我不希望人们意外地实例化实现(例如使用代码完成),遗憾的是,这对我不起作用,因为服务实现可能由第三方捆绑。该服务是一个SPI,由其他开发人员实现,但在我的代码知道其他代码之前,他们的代码无法运行。所以没有人可以调用registerService()。这就是我使用ServiceLoader的原因。从完全不同的角度来看,这是一种非常有趣的方法。感谢分享,虽然它不适用于Java。我希望Java中有某种机制可以这样做,但不幸的是,事实并非如此。我已经很久没有使用Java了,所以我不记得可能有帮助的小细节。嗯,这就是我所期望的。可能是图书馆提供了一个POM模板。但是包私有ServiceLoader不是一种有效的方法吗?你有没有具体的理由来整理这种方法?谢谢。不,私人包裹也可以。只是大多数情况下,一些(低级)类必须是公共的。