根据是否加载可选模块公开不同方法的类 [英] A class that exposes different methods depending on whether an optional module is loaded

查看:72
本文介绍了根据是否加载可选模块公开不同方法的类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个由多个模块组成的库:

I have a library consisting of multiple modules:

  • 核心
  • 番石榴

core 模块是强制性的,而 guava 是可选的.还有其他可选模块(这个问题代表一个最小的测试用例).

The core module is mandatory, while guava is optional. There are other optional modules (this question represents a minimal testcase).

每个模块公开一组用户可以调用的方法:

Each module exposes a set of methods that the user can invoke:

class CoreVerifier
{
  MapVerifier verify(Map);
}

class GuavaVerifier
{
  MultimapVerifier verify(Multimap);
}

我想要的

  • 为用户提供一个在一个地方导出所有方法的类:

    What I want

    • Provide users a class that exports all the methods in a single place:

      class UnifiedVerifier
      {
        MapVerifier verify(Map);
        MultimapVerifier verify(Multimap);
      }
      

    • 我希望用户能够使用这个类,即使在运行时缺少可选模块(例如 guava).意思是,UnifiedVerifier 是用类路径上的所有库编译的,但在运行时 MultimapVerifier 不存在第二个方法引用的 MultimapVerifier.

    • I want users to be able to use this class even if optional modules (e.g. guava) are missing at runtime. Meaning, the UnifiedVerifier is compiled with all libraries on the classpath but at runtime MultimapVerifier referenced by the second method is not present.

      • 如果用户从应用程序代码 javac 调用第一个方法失败:

      • If users invoke the first method from application code javac fails with:

      Application.java: cannot access MultimapVerifier
        class file for MultimapVerifier not found
      

    • 意思是,即使第一个方法是明确定义的(核心模块在编译时可用)编译器拒绝继续,因为第二个方法(他们没有使用)正在引用一个从类路径.

      Meaning, even though the first method is well-defined (the core module is available at compile-time) the compiler refuses to proceed because the second method (which they are not using) is referencing a class which is missing from the classpath.

      有没有办法在 Java 中实现这种事情?

      Is there a way to achieve this sort of thing in Java?

      assertj 有一个聪明的静态导入机制,他们声明一个不同的Assertions 每个模块(核心、番石榴)和 Java 的静态导入类根据您传入的类型选择正确的方法.我已经在使用类似的静态方法机制,但现在我想要类似的东西对于我不能使用静态方法的情况.

      assertj has a clever static-import mechanism whereby they declare a different Assertions class per module (core, guava) and Java's static import picks up the right method depending on the types you pass in. I am already using a similar mechanism for static methods, but now I want something similar for a case where I can't use static methods.

      推荐答案

      我想出了一个办法!您可以使用类阴影来实现所需的行为.

      I figured out a way! You can use class shadowing to achieve the desired behavior.

      1. 声明两个模块:
        • 核心
        • 番石榴
      • CoreVerifiers
      • GuavaVerifiers

      对于步骤 2 中的每个接口,在核心模块中声明一个具有委托给现有验证器的默认方法的接口.例如:

      For each interface in step 2, declare an interface in the core module with default methods that delegate to an existing verifier. For example:

      public interface ForwardingCoreVerifiers
      {
        CoreVerifiers coreVerifiers();
      
        default CoreVerifiers method1()
        {
          coreVerifiers().method1();
        }
      }
      

    • 最后,在核心库中,声明一个扩展所有转发接口的实现:

    • Finally, in the core library, declare an implementation that extends all of the forwarding interfaces:

      public final class Verifiers
        implements ForwardingCoreVerifiers, ForwardingGuavaVerifiers
      {
        public CoreVerifiers coreVerifiers()
        {
          return new CoreVerifiersImpl(...);
        }
        public CoreVerifiers guavaVerifiers()
        {
          return new GuavaVerifiersImpl(...);
        }
      }
      

    • 现在是魔法:

      • 如果用户在他们的类路径中包含核心模块,那么编译器将阻止他们调用任何与番石榴相关的方法.
      • 但是,如果用户在 classpath 中的核心模块前面包含 guava 模块,那么用户会突然看到与 guava 相关的方法(因为 guava 模块 GuavaVerifier 接口将隐藏在核心模块).
      • If users include the core module in their classpath then the compiler will prevent them from invoking any guava-related methods.
      • But, if users include the guava module in front of the core module on the classpath then suddenly users will see the guava-related methods (because the guava module GuavaVerifier interface will shadow the interface found in the core module).

      性能提示:

      • 在 Java 8 中,默认方法的性能不如抽象类:https://stackoverflow.com/a/30314501/14731
      • 因此,我建议为核心功能使用抽象类 (CoreVerifiers),并为其余模块使用默认方法 (GuavaVerifiers)
      • In Java 8, default methods don't perform as well as abstract classes: https://stackoverflow.com/a/30314501/14731
      • As such, I recommend using an abstract class for the core functionality (CoreVerifiers) and using default methods for the remaining modules (GuavaVerifiers)

      更新:我为 Java 9 发布了一个更新问题.

      UPDATE: I have posted an updated question for Java 9.

      这篇关于根据是否加载可选模块公开不同方法的类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆