java - пример - Динамически ссылаться на правильную реализацию на заводе




switch case java пример (2)

Другой вариант - использовать подход Service Loader .

Наличие ваших исполнителей добавит что-то вроде следующего в ./resources/META-INF/services/your.package.HostExtractor :

their.package1.HostExtractorABC
their.package2.HostExtractorDEF
their.package3.HostExtractorGHI
...

Затем в вашем коде вы можете иметь что-то вроде:

HostExtractorFactory() {
    final ServiceLoader<HostExtractor> loader
            = ServiceLoader.load(your.package.HostExtractor.class);

    for (final HostExtractor registeredExtractor : loader) {
        // TODO - Perform pre-processing which is required.
        // Add to Map?  Extract some information and store?  Etc.
    }
}

У меня есть библиотека, которая анализирует 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 + "]");
    }
}

}

Проблема заключается в том, что пользователи запрашивают больше 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);
    }
}

}

И пользователь будет использовать его таким образом:

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;
}
...

}

Я похлопал себя по спине, когда понял, что это никогда не сработает: классы пользователей не загружаются, когда я получаю URL-адрес, только фабрика, что означает, что их конструктор никогда не запускается, а карта всегда пуста. Поэтому я вернулся к чертежной доске, но хотел бы, чтобы некоторые идеи касались того, чтобы это работало, или другого подхода, чтобы избавиться от этого отвратительного оператора switch.

S


Я бы посоветовал вам узнать об инъекции зависимостей (мне нравится реализация весны ). Затем вы сможете написать интерфейс, как

public interface HostExtractorHandler {
    public String getName();
    public HostExtractor getInstance();
}

Чем ваш код может «спросить» все классы, реализующие этот интерфейс, тогда вы сможете построить свою карту на этапе инициализации своего класса.





switch-statement