【问题标题】:Java (Android) library project - How to design optional modules?Java (Android) 库项目 - 如何设计可选模块?
【发布时间】:2016-01-23 18:47:58
【问题描述】:

我正在创建一个基于 Android (Java) 的库项目 (JAR),其中有 -

  1. 核心功能
  2. 可选功能

现在由于大小限制,我必须将此 JAR 分解为 JAR 集合,该库的用户将可以灵活地包含可选 JAR。同时,要求为用户提供单一接口,使用该接口他们应该能够调用核心和可选API。为此,我想到了两种解决方案 -

解决方案-1 核心库中有接口的类实现,这里实现了与核心特性相关的API,但可选特性的API会通过反射从这里调用,所以如果找到类,则表明包含可选库,否则不包含。

APIInterface.java

public interface APIInterface {
    public void coreMethod();
    public void optionalMethod();
}

CoreClass.java

public class CoreClass implements APIInterface {
  public void coreMethod() {
    // implementation
  }
  public void optionalMethod() {
    // use reflection to access optional method from OptionalClass
  }
}

OptionalClass.java

public class OptionalClass {
  public void optionalMethod() {
    new CoreClass().utilityMethod(); // or super.utilityMethod();
    // implementation
  }
}

Pros - 这里只有 optional 包括 core(用于核心实用方法),core 不包括可选。所以没有循环依赖。
缺点 - 使用反射

解决方案 2 为避免解决方案 1 中提到的反射,请创建两个版本的可选库。首先是完整实现,第二个是空实现(仅包装器)。用户必须强制包含其中任何一个,这取决于用户是否需要可选功能。这样,依赖性将被反转。因此,core 默认会包含可选库,并且可以从可选库中调用 API 而无需反射。

APIInterface.java

public interface APIInterface {
    public void coreMethod();
    public void optionalMethod();
}

CoreClass.java

public class CoreClass implements APIInterface {
  public void coreMethod() {
    // implementation
  }
  public void optionalMethod() {
    new OptionalClass().optionalMethod();
  }
}

OptionalClass.java // 完整实现

public class OptionalClass {
  public void optionalMethod() {
    new CoreClass().utilityMethod(); // or super.utilityMethod();
    // optional implementation
  }
}

OptionalClass.java // 空实现

public class OptionalClass {
  public void optionalMethod() {
    // do nothing
  }
}

优点 - 没有反射
缺点 - 1. core 和 optional 存在循环依赖,因为 core 包含 optional 来调用 optional API,而 optional 包含 core 使用核心实用程序和服务。
2. 用户必须强制包含可选的 JAR(完整或空实现)

您推荐哪种解决方案或其他更好的解决方案?请提出建议。

【问题讨论】:

    标签: java android reflection jar circular-dependency


    【解决方案1】:

    您可以使用桥接模式。在core文件中为每个可选jar文件提供一个接口,在可选jar中实现接口。

    // in the core jar file
    public interface Optional {
        void optionalMethod();
    }
    
    // in the optional jar file
    public class OptionalImpl implements Optional {
        public void optionalMethod() {
            // implementation
        }
    }
    

    现在,为 CoreClass 创建一个 Builder,您可以在其中相应地设置实现。

    CoreClass coreClass = new CoreClass.Builder()
        .setOptional(new OptionalImpl())
        .build();
    

    在 CoreClass 中,检查是否存在实现,并相应地委派调用。

    public class CoreClass implements APIInterface {
        // is set via Builder
        private Optional optional = null; 
    
        public void coreMethod() {
            // implementation
        }
    
        public void optionalMethod() {
            if(optional != null) {
                optional.optionalMethod();
            }
        }
    }
    

    【讨论】:

    • 是的,您的解决方案是正确的。这就是我在寻求解决方案 1 和 2 之前所做的。但是在这里我想要实现的是,当包含或不包含可选库时,该库的用户不应进行代码更改。因此,无论是否包含可选 jar,用户都不需要以不同的方式构建 coreClass。我要避免的只是在包含可选 jar 时在用户端创建任何对象(这里是 new OptionalImpl())。另外,您能否建议在解决方案 1 和 2 中,您更喜欢哪一个?谢谢。
    • 我仍然会使用我的解决方案,但如果存在 Optional 类,则动态检查 CoreClass 的构造函数,如果存在,则按上述方式创建和设置实现。 try { Class optionalClass = Class.forName("my.package.Optional"); optional = (Optional) optionalClass.newInstance(); } catch(Exception ignore) { }.
    • 感谢您的建议。正如我在解决方案 1 中提到的,使用 Class.forName 动态检查可选类基本上是反射。我会这样做,因为我没有看到任何其他建议或 cmets。
    • 是的,它使用反射,但仅在创建类时,而不是每次调用可选方法时。因此,这种解决方案可以最大限度地减少反射带来的开销。
    猜你喜欢
    • 2015-06-10
    • 1970-01-01
    • 1970-01-01
    • 2018-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-01
    • 1970-01-01
    相关资源
    最近更新 更多