如何允许第三方在我的 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路径。
我在 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")
.
另一种方法是使用服务 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路径。