如何允许第三方在我的 java 库中扩展 类

How to allow third party to extend classes in my java library

我在 java 中有一个父 class 定义了一些行为

public class ParentClass {
    public ParentClass() {
        //Do some instantiation
    }

    public void doWork() {
       //Do some behavior defined by the parent class
    }
}

现在我的项目中还有其他一些 class 使用了它。假设它用于 main

public class Main {

    public static void main(String [] args) {
        ParentClass parent = new ParentClass();
        parent.doWork();
    }

}

现在假设我的项目设置为供其他开发人员使用的库。我希望他们能够扩展 ParentClass 并根据自己的喜好覆盖 doWork() 方法。如果开发人员不能更改 Main class,我如何确保 ChildClass 在 main() 中实例化而不是在 ParentClass 中实例化?

子类示例

public class ChildClass extends ParentClass {
    public ChildClass() {
        super();
        //Do some more instantiation
    }

    @Override
    public void doWork() {
       super.doWork();
       //Do some more behavior in child class
    }
}

好吧,似乎有很多方法可以做到这一点。一种简单的方法是让客户端将 child class 的名称作为系统 属性 传递。 main 可以使用 System.getProperty("prop.name").

访问 class 名称

另一种方法是使用服务 API 来寻找实施 classes。参见 https://docs.oracle.com/javase/tutorial/ext/basics/spi.html#the-serviceloader-class

话虽如此,您描述的内容很奇怪,因为客户端代码本身通常应该有自己的 main

图书馆一开始就不应该有主 class。确定您要交付的主要内容:应用程序或库。

或者您正在寻找的可能是抽象工厂模式。

无需依赖您提供的主要方法。如果他们可以扩展您的 class,他们可以在他们的 own 主方法中创建他们扩展 class 的对象。

这取决于你想要实现什么,如果你的库打算被另一个第 3 方使用,那么你的主要方法很可能是无关紧要的,因为你的 JAR 包将被捆绑在他自己的 JAR 中,这只会允许一个主 class;他的

此方法可能需要您有一些触发器来启动您的 class(引擎?),这同样取决于您希望客户如何使用您的 API。

此外,您可以检查模板方法设计模式,因为它可能对您的情况有用,本质上,它允许您确定算法的粗线并定义您希望客户使用的部分 redefine/extend.

您可以使用 java.util.ServiceLoader 加载 ParentClass 的实例,但您需要考虑一些事项:

  • 需要将文件添加到包含 class 实现 ParentClass、文件名 META-INF/services/ParentClass 的 jar(将 ParentClass 替换为 class 实施)。对于每个 class 实现 ParentClass,您需要向该文件添加一行,其中包含实现 class.
  • 的完全限定名称
  • 所有这些 classes 都需要支持使用 public 无参数构造函数创建 class。

例子

你的罐子

package mypackage;
// used interface here, since in this case there's no reason to use
// a class
// you could use a class here too
public interface ParentClass {
    public void doWork();
}
public class Main {

    public static void main(String [] args) {
        // execute doWork of every ParentClass provided
        for (ParentClass parent : ServiceLoader.load(mypackage.ParentClass.class)) {
            parent.doWork();
        }
    }

}

jar 实现 ParentClass

package mypackage2;

public class ImplementingClass implements ParentClass {

    @Override
    public void doWork() {
       // Custom implementation
       System.out.println("Hello world");
    }
}

META-INF/services/mypackage.ParentClass

mypackage2.ImplementingClass

然后你只需要在执行你的程序时将另一个 jar 添加到你的 class路径。