在运行时交换算法的最佳实践或设计是什么?
What is a good practice or design to swap algorithms at runtime?
我有几种数据处理算法可以组合成一个管道来转换数据。代码分为两个组件:执行数据加载相关任务的预处理组件和处理管道组件。
我目前已将这两部分编译并打包到两个单独的 jar 中。这个想法是可以将同一个预处理 jar 运送给所有客户,但管道 jar 可以根据客户要求进行交换。我想保持代码简单并尽量减少配置,从而排除使用 OSGi 或 CDI 框架。
我通过查看 SLF4J 的实现获得了一些提示。该项目分为两部分:核心 API 和包装不同日志记录 API 的一堆实现。核心 API 调用虚拟 classes(存在于核心项目中只是为了允许编译),这些调用将被日志项目中发现的相同 classes 覆盖。在构建时,已编译的虚拟 classes 在打包到 jar 之前从核心 API 中删除。 运行时,需要在class路径下包含core jar和logging jar,core jar中缺失的class文件将由来自的文件填充伐木罐。这工作正常,但对我来说感觉有点老套。我想知道是否有更好的设计,或者这是否是不使用 CDI 框架的最佳设计。
听起来像是策略软件设计模式。
Example Suppose we have a service type com.example.CodecSet
which is
intended to represent sets of encoder/decoder pairs for some protocol.
In this case it is an abstract class with two abstract methods:
public abstract Encoder getEncoder(String encodingName);
public abstract Decoder getDecoder(String encodingName);
Each method returns an appropriate object or null
if the provider does
not support the given encoding. Typical providers support more than one
encoding. If com.example.impl.StandardCodecs
is an implementation of
the CodecSet
service then its jar file also contains a file named
META-INF/services/com.example.CodecSet
This file contains the single line:
com.example.impl.StandardCodecs # Standard codecs
The CodecSet
class creates and saves a single service instance at
initialization:
private static ServiceLoader<CodecSet> codecSetLoader
= ServiceLoader.load(CodecSet.class);
To locate an encoder for a given encoding name it defines a static factory method which iterates
through the known and available providers, returning only when it has
located a suitable encoder or has run out of providers.
public static Encoder getEncoder(String encodingName) {
for (CodecSet cp : codecSetLoader) {
Encoder enc = cp.getEncoder(encodingName);
if (enc != null)
return enc;
}
return null;
}
A getDecoder
method is defined similarly.
您已经了解如何使用它的要点:
- 将您的项目分成几个部分(核心、实施 1、实施 2、...)
- 使用预处理器
运送核心API
- 让每个实现都将正确的 META-INF 文件添加到其 .jar 文件中。
唯一需要的配置文件是您打包到 .jar 文件中的配置文件。
您甚至可以通过注释为您 automatically generated:
package foo.bar;
import javax.annotation.processing.Processor;
@AutoService(Processor.class)
final class MyProcessor extends Processor {
// …
}
AutoService
will generate the file
META-INF/services/javax.annotation.processing.Processor
in the output classes folder. The file will contain:
foo.bar.MyProcessor
我有几种数据处理算法可以组合成一个管道来转换数据。代码分为两个组件:执行数据加载相关任务的预处理组件和处理管道组件。
我目前已将这两部分编译并打包到两个单独的 jar 中。这个想法是可以将同一个预处理 jar 运送给所有客户,但管道 jar 可以根据客户要求进行交换。我想保持代码简单并尽量减少配置,从而排除使用 OSGi 或 CDI 框架。
我通过查看 SLF4J 的实现获得了一些提示。该项目分为两部分:核心 API 和包装不同日志记录 API 的一堆实现。核心 API 调用虚拟 classes(存在于核心项目中只是为了允许编译),这些调用将被日志项目中发现的相同 classes 覆盖。在构建时,已编译的虚拟 classes 在打包到 jar 之前从核心 API 中删除。 运行时,需要在class路径下包含core jar和logging jar,core jar中缺失的class文件将由来自的文件填充伐木罐。这工作正常,但对我来说感觉有点老套。我想知道是否有更好的设计,或者这是否是不使用 CDI 框架的最佳设计。
听起来像是策略软件设计模式。
Example Suppose we have a service type
com.example.CodecSet
which is intended to represent sets of encoder/decoder pairs for some protocol. In this case it is an abstract class with two abstract methods:public abstract Encoder getEncoder(String encodingName); public abstract Decoder getDecoder(String encodingName);
Each method returns an appropriate object or
null
if the provider does not support the given encoding. Typical providers support more than one encoding. Ifcom.example.impl.StandardCodecs
is an implementation of theCodecSet
service then its jar file also contains a file namedMETA-INF/services/com.example.CodecSet
This file contains the single line:
com.example.impl.StandardCodecs # Standard codecs
The
CodecSet
class creates and saves a single service instance at initialization:private static ServiceLoader<CodecSet> codecSetLoader = ServiceLoader.load(CodecSet.class);
To locate an encoder for a given encoding name it defines a static factory method which iterates through the known and available providers, returning only when it has located a suitable encoder or has run out of providers.
public static Encoder getEncoder(String encodingName) { for (CodecSet cp : codecSetLoader) { Encoder enc = cp.getEncoder(encodingName); if (enc != null) return enc; } return null; }
A
getDecoder
method is defined similarly.
您已经了解如何使用它的要点:
- 将您的项目分成几个部分(核心、实施 1、实施 2、...)
- 使用预处理器 运送核心API
- 让每个实现都将正确的 META-INF 文件添加到其 .jar 文件中。
唯一需要的配置文件是您打包到 .jar 文件中的配置文件。
您甚至可以通过注释为您 automatically generated:
package foo.bar; import javax.annotation.processing.Processor; @AutoService(Processor.class) final class MyProcessor extends Processor { // … }
AutoService
will generate the fileMETA-INF/services/javax.annotation.processing.Processor
in the output classes folder. The file will contain:
foo.bar.MyProcessor