2017-07-28 1 views
0

if/elseがたくさんあるレガシーコードに取り組んでいます。条件付き分解および/またはガード・ステートメントなどを使用してそれをクリーニングすることができます。使用できるもう1つのアプローチは、分岐から関数を作成し、これらの関数をチェーンとして実行し、最初の応答で終了することです。私はファンクションチェーンを使用することが過度なのか疑問に思っていますか?どんなビュー?他のブランチがあれば、関数の連鎖を使ってコードを削除しても意味がありますか?

私のチェーンは以下のようになります。これは簡単な例です。

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

EDIT

ジェネリックエグゼキュータのようなものである可能性があります。それは私の心を横切った単なる考えでした。私はそれが私の同僚のためにそれをもっと秘密にすると感じました。しかし、if/elseを削除するのは本当に好きです。私はOOPSに行きました(多態性)。

答えて

0

私の見解では、最初のバージョンははるかに簡単で読みやすいように見えます。したがって、2番目のバージョンではパフォーマンスに勝利がない場合、私はそれに従います。いくつかの一般的な方法の抽出は良いでしょうが、それはそれぞれStateValidatorが異なって見えるのでそれほど単純ではないようです。

関連する問題