使用函数链减少if else分支和清理代码是否有意义

时间:2017-07-28 16:19:24

标签: java if-statement design-patterns lambda refactoring

我正在研究有很多if / else的遗留代码。我可以使用条件分解和/或保护语句等来清理它。可以使用的另一种方法是从分支创建函数,并通过第一响应执行这些函数作为链和退出。我想知道使用功能链是否过度杀伤?有意见吗?

我的链看起来像下面。这是一个简化的例子。

public class RequestStateHandler {
    private final List<Function<RequestStateInfo, Optional<Response>>> handlers = new ArrayList<>();

    public RequestStateHandler() {
        handlers.add(requestStateInfo -> xStateValidator(requestStateInfo));
        handlers.add(requestStateInfo -> yStateValidator(requestStateInfo));
        handlers.add(requestStateInfo -> zStateValidator(requestStateInfo));
    }

    public Response getResponse(RequestStateInfo requestStateInfo) {
        try {
            for (final Function<RequestStateInfo, Optional<Response>> handler : handlers) {
                final Optional<Response> response = handler.apply(requestStateInfo);

                if (response.isPresent()) {
                    return response.get();
                }
            }
        } catch (Exception e) {
            LOGGER.error("Some log", e);
        }

        return getDefaultResponse(requestStateInfo);
    }

    private Optional<Response> xStateValidator(RequestStateInfo requestStateInfo) {
        final A a = requestStateInfo.getA();
        if (a.isABC()) {
            return Optional.of(requestStateInfo.getX());
        }

        return Optional.empty();
    }

    private Optional<Response> yStateValidator(RequestStateInfo requestStateInfo) {
        if (requestStateInfo.isXYZ()) {
            final Response response = requestStateInfo.getX();
            final A a = response.getA();
            if (a.isSomeOtherTest()) {
                return Optional.of(response);
            }
        }

        return Optional.empty();
    }

    private Optional<Response> zStateValidator(RequestStateInfo requestStateInfo) {
        final Response response = requestStateInfo.getX();
        final A a = response.getA();
        if (a.isSomeAnotherTest()) {
            return Optional.of(response);
        }

        return Optional.of(getDefaultResponse(requestStateInfo));
    }

    private Response getDefaultResponse(RequestStateInfo requestStateInfo) {
        return new Response(A.create(requestStateInfo.getY()), null, null, null);
    }
}

我想创建一个可重用的执行程序,以便我们在这里只能拥有业务逻辑。对我来说,它看起来更干净,但它显然添加依赖性来按顺序执行功能。我会说,像责任链一样。你有什么想法?

通用执行程序可能类似于:

import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

public class ChainedExecutor<T, R> {
    private final static Logger LOGGER = LoggerFactory.getLogger(ChainedExecutor.class);
    public final List<Function<T,Optional<R>>> handlers;
    private R defaultResponse;

    private ChainedExecutor() {
        this.handlers = new ArrayList<>();
    }

    public R execute(T request) {
        return execute(request, Optional.empty(), Optional.empty());
    }

    public R execute(T request, Function<T, R> defaultSupplier) {
        return execute(request, Optional.of(defaultSupplier), Optional.empty());
    }

    public R execute(T request, Consumer<Exception> exceptionHandler) {
        return execute(request, Optional.empty() ,Optional.of(exceptionHandler));
    }

    public R execute(T request, Function<T, R> defaultHandler, Consumer<Exception> exceptionHandler) {
        return execute(request, Optional.of(defaultHandler), Optional.of(exceptionHandler));
    }

    public R execute(T request, Supplier<R> defaultSupplier) {
        final Function<T, R> defaultHandler = (input) -> defaultSupplier.get();
        return execute(request, Optional.of(defaultHandler), Optional.empty());
    }

    private R execute(T request, Optional<Function<T, R>> defaultHandler, Optional<Consumer<Exception>> exceptionHandler) {
        Optional<R> response;
        try {
            for (final Function<T,Optional<R>> handler: handlers) {
                response = handler.apply(request);

                if (response.isPresent()) {
                    return response.get();
                }
            }
        }
        catch (Exception exception) {
            handleOrLog(exceptionHandler, exception);
        }

        return getDefaultResponse(defaultHandler, request);
    }

    private void handleOrLog(Optional<Consumer<Exception>> exceptionHandler, Exception exception) {
        if (exceptionHandler.isPresent()) {
            exceptionHandler.get().accept(exception);
            return;
        }
        LOGGER.error("Unhandled exception occurred while executing handler chain. This most probably is a developer error.");
    }

    private R getDefaultResponse(Optional<Function<T, R>> defaultHandler, T request) {
        if (defaultHandler.isPresent()) {
            return defaultHandler.get().apply(request);
        }
        return getDefaultResponse();
    }

    public R getDefaultResponse() {
        return defaultResponse;
    }

    public static class Builder<T, R> {
        private final ChainedExecutor<T, R> chainedExecutor = new ChainedExecutor<>();

        public Builder(List<Function<T,Optional<R>>> handlers) {
            Validate.notNull(handlers);
            for (final Function<T, Optional<R>> handler: handlers) {
                Validate.notNull(handler);
                handlers.add(handler);
            }
        }

        public Builder() {}

        public ChainedExecutor.Builder<T, R> withHandler(Function<T, Optional<R>> handler) {
            Validate.notNull(handler);
            chainedExecutor.handlers.add(handler);
            return this;
        }

        public ChainedExecutor.Builder<T, R> withDefaultResponse(R defaultResponse) {
            Validate.notNull(defaultResponse);
            chainedExecutor.defaultResponse = defaultResponse;
            return this;
        }

        public ChainedExecutor<T, R> build() {
            Validate.isTrue(!chainedExecutor.handlers.isEmpty());
            return chainedExecutor;
        }
    }
}

修改

我最终没有这样做。这只是我想到的一个想法。我觉得这会让同事们更加神秘。虽然,我真的很喜欢删除if / else。我去了OOPS方式(多态)。

1 个答案:

答案 0 :(得分:0)

从我的观点来看,第一个版本看起来更简单,更容易阅读,因此如果在第二个版本中没有性能获胜,我会继续使用它。提取一些通用方法会很好,但似乎不是那么直截了当,因为每个StateValidator看起来都不同。