在运行时交换算法的最佳实践或设计是什么?

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 框架的最佳设计。

听起来像是策略软件设计模式。

https://en.wikipedia.org/wiki/Strategy_pattern

看看ServiceLoader

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