动态调用工厂中的正确实现

San*_*eru 6 java switch-statement

我有一个解析URL并提取一些数据的库.每个URL有一个类.要知道哪个类应该处理用户提供的URL,我有以下代码.

public class HostExtractorFactory {

private HostExtractorFactory() {
}

public static HostExtractor getHostExtractor(URL url)
        throws URLNotSupportedException {
    String host = url.getHost();

    switch (host) {
    case HostExtractorABC.HOST_NAME:
        return HostExtractorAbc.getInstance();
    case HostExtractorDEF.HOST_NAME:
        return HostExtractorDef.getInstance();
    case HostExtractorGHI.HOST_NAME:
        return HostExtractorGhi.getInstance();
    default:
        throw new URLNotSupportedException(
                "The url provided does not have a corresponding HostExtractor: ["
                        + host + "]");
    }
}
Run Code Online (Sandbox Code Playgroud)

}

问题是用户要求解析更多的URL,这意味着我的switch语句正在增长.每当有人提出解析器时,我都必须修改我的代码以包含它.

为了结束这个,我决定创建一个地图并将它暴露给它们,这样当他们的类被编写时,他们可以通过向工厂提供主机名和提取器来将自己注册到工厂.以下是实施此想法的工厂.

public class HostExtractorFactory {

private static final Map<String, HostExtractor> EXTRACTOR_MAPPING = new HashMap<>();

private HostExtractorFactory() {
}

public static HostExtractor getHostExtractor(URL url)
        throws URLNotSupportedException {
    String host = url.getHost();

    if(EXTRACTOR_MAPPING.containsKey(host)) {
        return EXTRACTOR_MAPPING.get(host);
    } else {
        throw new URLNotSupportedException(
                "The url provided does not have a corresponding HostExtractor: ["
                        + host + "]");
    }
}

public static void register(String hostname, HostExtractor extractor) {
    if(StringUtils.isBlank(hostname) == false && extractor != null) {
        EXTRACTOR_MAPPING.put(hostname, extractor);
    }
}
Run Code Online (Sandbox Code Playgroud)

}

并且用户将以这种方式使用它:

public class HostExtractorABC extends HostExtractor {

public final static String HOST_NAME = "www.abc.com";

private static class HostPageExtractorLoader {
    private static final HostExtractorABC INSTANCE = new HostExtractorABC();
}

private HostExtractorABC() {
    if (HostPageExtractorLoader.INSTANCE != null) {
        throw new IllegalStateException("Already instantiated");
    }

    HostExtractorFactory.register(HOST_NAME, this);
}

public static HostExtractorABC getInstance() {
    return HostPageExtractorLoader.INSTANCE;
}
...
Run Code Online (Sandbox Code Playgroud)

}

当我意识到这将永远无法工作时,我正在拍拍我自己的背:当我收到URL时,用户类没有加载,只有工厂,这意味着他们的构造函数永远不会运行,并且地图总是空的.所以我回到了绘图板,但想要一些关于让它工作的想法或另一种方法来摆脱这个讨厌的switch语句.

小号

Roe*_*rel 1

我建议您了解依赖注入(我喜欢spring实现)。然后你就可以编写一个像这样的接口

public interface HostExtractorHandler {
    public String getName();
    public HostExtractor getInstance();
}
Run Code Online (Sandbox Code Playgroud)

您的代码可以“询问”实现此接口的所有类,然后您就可以在类的初始化阶段构建映射。