根据变量选择实现 (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。
问题:
- 在 Python 中是否有更好的方法来实现类似的功能?
奖金:
- 这有具体的模式吗?怎么称呼?
- 这是在 Java 中实现的正确方法吗?
我总是阅读很多关于工厂、抽象工厂模式的文章,但不确定我是否可以替换父级内部的类型检查 class。
您可以使用方法工厂模式。请参阅此处的示例:
http://javarevisited.blogspot.se/2011/12/factory-design-pattern-java-example.html
在示例中,将货币替换为文件,将货币符号替换为文件扩展名。
在 Java 中,使用一个 enum
。让我们以 jpg
和 gif
为例。假设我们有 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...您可以只使用普通词典:-) .
我有几个 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。
问题:
- 在 Python 中是否有更好的方法来实现类似的功能?
奖金:
- 这有具体的模式吗?怎么称呼?
- 这是在 Java 中实现的正确方法吗?
我总是阅读很多关于工厂、抽象工厂模式的文章,但不确定我是否可以替换父级内部的类型检查 class。
您可以使用方法工厂模式。请参阅此处的示例: http://javarevisited.blogspot.se/2011/12/factory-design-pattern-java-example.html 在示例中,将货币替换为文件,将货币符号替换为文件扩展名。
在 Java 中,使用一个 enum
。让我们以 jpg
和 gif
为例。假设我们有 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...您可以只使用普通词典:-) .