根据变量选择实现 (class)

Selecting implementation (class) depending on variable

我有几个 classes 处理不同的文件扩展名。他们都实现了一个公共接口或扩展了相同的抽象 class。我想根据文件的扩展名动态地(运行时)获取正确的 subclass。

现在我有点不知道将逻辑放置到 select 正确实现的位置。 经过一番思考后,我现在会在父 class 中创建一个 dict 来执行 selection。 例如

{"jpg": jpgProcessor,
"gif": gifProcessor}.get(fileExt)().process(file)

在 Java 中,我将在父 Class 中创建一个注册方法,该方法由子 classes 的静态块调用。 parentClass 然后会有一个 getFilter(String fileExt) 方法,它 select 是 HashMap 或类似东西中的正确 Class。

问题:

奖金:

我总是阅读很多关于工厂、抽象工厂模式的文章,但不确定我是否可以替换父级内部的类型检查 class。

您可以使用方法工厂模式。请参阅此处的示例: http://javarevisited.blogspot.se/2011/12/factory-design-pattern-java-example.html 在示例中,将货币替换为文件,将货币符号替换为文件扩展名。

在 Java 中,使用一个 enum。让我们以 jpggif 为例。假设我们有 3 类:

class Processor {}
class JpgProcessor extends Processor {}
class GifProcessor extends Processor {}

我们现在可以使用 enum 工厂模式来创建实例:

enum ProcessorFactory implements Supplier<Processor> {
    JPG("jpg", JpgProcessor::new),
    GIF("gif", GifProcessor::new);

    private static final ProcessorFactory[] VALUES = values();
    private final String extension;
    private final Supplier<? extends Processor> supplier;


    private ProcessorFactory(String extension, Supplier<? extends Processor> supplier) {
        this.extension = extension;
        this.supplier = supplier;
    }

    public static ProcessorFactory fromExtension(final String extension) {
        return Arrays.stream(VALUES)
                .filter(v -> v.extension.equals(extension))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException("Invalid extension " + extension + "."));
    }

    @Override
    public Processor get() {
        return supplier.get();
    }
}

这里发生了很多事情。首先,enum implements Supplier<Processor>,这意味着您可以使用它来获取 Processor 实例,如下所示:

final Processor jpgProcessor = ProcessorFactory.JPG.get(); 

接下来,每个 enum 都有一个 String extension,这些用于将特定的 enum 实例绑定到特定的扩展。 fromExtension 方法就是这样做的,因此您可以使用以下方法获得正确的值:

final ProcessorFactory factory = ProcessorFactory.fromExtension("jpg");

因此,要从扩展中获得 Processor,您需要做的就是:

final Processor jpgProcessor = ProcessorFactory.fromExtension("jpg").get(); 

这假设您需要为每个交互 new Processor()。如果你不需要它,那么一个简单的 Map<String, Processor> 也可以工作:

final Map<String, Processor> map = new HashMap<>();
map.put("jpg", new JpgProcessor());
map.put("gif", new GifProcessor());

获取处理器:

final Processor processor = map.get("jpg");

我不知道 Java...在 python 中,我可能会这样做:

class ProcessorSelector(object):
    def __init__(self):
        self._processor_map = {}

    def register(self, type, processor):
        # type checking goes here if you're worried about it...
        # e.g. `if not isinstance(processor, Processor): raise TypeError`
        self._processor_map[type] = processor

    def select(self, type):
        return self._processor_pam[type]

selector = ProcessorSelector()
selector.register('jpg', JpgProcessor)
cls = selector.select('jpg')
processor = cls()
processor.process(file)

当然,您实际上根本不需要 ProcessorSelector class...您可以只使用普通词典:-) .