Рефлектор Java

Я пытаюсь найти хороший способ реализации службы, которая опирается на сторонний класс библиотеки. У меня также есть реализация по умолчанию для использования в качестве резервной копии, если библиотека недоступна или не может предоставить ответ.

public interface Service {

    public Object compute1();

    public Object compute2();
}

public class DefaultService implements Service {

    @Override
    public Object compute1() {
       // ...
    }

    @Override
    public Object compute2() {
        // ...
    }
}

Фактическая реализация службы будет выглядеть примерно так:

public class ServiceImpl implements Service {
    Service defaultService = new DefaultService();
    ThirdPartyService thirdPartyService = new ThirdPartyService();

    @Override
    public Object compute1() {
        try {
            Object obj = thirdPartyService.customCompute1();
            return obj != null ? obj : defaultService.compute1();
        } 
        catch (Exception e) {
            return defaultService.compute1();
        }
    }

    @Override
    public Object compute2() {
        try {
            Object obj = thirdPartyService.customCompute2();
            return obj != null ? obj : defaultService.compute2();
        } 
        catch (Exception e) {
            return defaultService.compute2();
        }
    }
}

Текущая реализация, похоже, дублирует некоторые вещи так, что только фактические вызовы служб разные, но механизм try/catch и по умолчанию почти одинаковый. Кроме того, если в сервисе был добавлен другой метод, реализация будет выглядеть почти одинаково.

Существует ли шаблон дизайна, который может применяться здесь (proxy, strategy), чтобы код выглядел лучше и делал дополнительные дополнения менее скопированной вставкой?

Ответ 1

Вы можете извлечь общую логику в отдельный метод с использованием ссылок на методы, например:

public class ServiceImpl implements Service {
    Service defaultService = new DefaultService();
    ThirdPartyService thirdPartyService = new ThirdPartyService();

    @Override
    public Object compute1() {
        return run(thirdPartyService::customCompute1, defaultService::compute1);
    }

    @Override
    public Object compute2() {
        return run(thirdPartyService::customCompute2, defaultService::compute2);
    }

    private static <T> T run(Supplier<T> action, Supplier<T> fallback) {
        try {
            T result = action.get();
            return result != null ? result : fallback.get();
        } catch(Exception e) {
            return fallback.get();
        }
    }
}

Ответ 2

Возможно, вам поможет прокси-сервер. Нижеприведенный пример непроверен, но должен дать вам представление о том, что вы можете создать:

public class FallbackService implements InvocationHandler {

    private final Service primaryService;
    private final Service fallbackService;

    private FallbackService(Service primaryService, Service fallbackService) {
        this.primaryService = primaryService;
        this.fallbackService = fallbackService;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            Object result = method.invoke(primaryService, args);
            if (result != null) return result;
        } catch (Exception ignore) {}
        return method.invoke(fallbackService, args);
    }

    public static Service createFallbackService(Service primaryService, Service fallbackService) {
        return (Service) Proxy.newProxyInstance(
                Service.class.getClassLoader(),
                new Class[] { Service.class },
                new FallbackService(primaryService, fallbackService)
        );
    }
}

Ответ 3

Одна из лучших библиотек для этого - Netflix Hystrix. Я не уверен, нужен ли вам такой тяжелый подъем. Это даст вам пул потоков, тайм-ауты, резервные копии, мониторинг, изменения конфигурации времени выполнения, короткое замыкание и т.д.

В основном это библиотека для защиты вашего кода от сбоев его зависимостей.