2016-08-02 3 views
4

중복 코드가 많은 두 가지 방법이 있지만 고유 한 비트가 전체적으로 발생하는 클래스가 있습니다. 내 연구에서 "Execute around method"패턴을 수행해야한다고 생각하지만, 복제 할 수없는 코드를 사용하는 것처럼 보이는 리소스를 찾을 수 없습니다.고유 한 부분이 루프/try-catch 내에있을 때 코드 중복 방지

나는 아래에 붙여 넣은 두 가지 방법 인 apiPost와 apiGet을 가지고 있습니다.

/** 
* Class that handles authorising the connection and handles posting and getting data 
* 
* @version  %I%, %G% 
* @since  1.0 
*/ 
public class CallHandler { 
    private static PropertyLoader props = PropertyLoader.getInstance(); 
    final static int MAX = props.getPropertyAsInteger(props.MAX_REQUESTS); 
    private final Logger log = LoggerFactory.getLogger(CallHandler.class); 
    private final static String POST = "POST"; 
    private final static String GET = "GET"; 

    /** 
    * Makes a POST call to the API URL provided and returns the JSON response as a string 
    * http://stackoverflow.com/questions/15570656/how-to-send-request-payload-to-rest-api-in-java 
    * 
    * @param urlString  the API URL to send the data to, as a string 
    * @param payload  the serialised JSON payload string 
    * @return    and value returned as a JSON string, ready to be deserialised 
    */ 
    public String apiPost(String urlString, String payload) { 
     boolean keepGoing = true; 
     int tries = 0; 

     String line; 
     StringBuilder jsonString = new StringBuilder(); 

     log.debug("Making API Call: {}", urlString); 

     while (keepGoing && tries < MAX) { 
      tries++; 
      try { 
       URL url = new URL(urlString); 

       HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 

       // UNIQUE CODE START 
       prepareConnection(connection, POST); 
       OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream(), "UTF-8"); 
       writer.write(payload); 
       writer.close(); 
       // UNIQUE CODE END 

       BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream())); 
       while ((line = br.readLine()) != null) { 
        jsonString.append(line); 
       } 
       br.close(); 
       connection.disconnect(); 
       keepGoing = false; 
      } catch (Exception e) { 
       log.warn("Try #{}. Error posting: {}", tries, e.getMessage()); 
       log.warn("Pausing for 1 second then trying again..."); 
       try { 
        TimeUnit.SECONDS.sleep(1); 
       } catch (InterruptedException f) { 
        log.warn("Sleeping has been interrupted: {}", f.getMessage()); 
       } 
      } 
     } 
     return jsonString.toString(); 
    } 

    /** 
    * Makes a GET call to the API URL provided and returns the JSON response as a string 
    * http://stackoverflow.com/questions/2793150/using-java-net-urlconnection-to-fire-and-handle-http-requests 
    * 
    * @param urlString  the API URL to request the data from, as a string 
    * @return    the json response as a string, ready to be deserialised 
    */ 
    public String apiGet(String urlString) { 
     boolean keepGoing = true; 
     int tries = 0; 

     String line; 
     StringBuilder jsonString = new StringBuilder(); 

     log.debug("Making API Call: {}", urlString); 

     while (keepGoing && tries < MAX) { 
      tries++; 
      try { 
       URL url = new URL(urlString); 

       HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 

       // UNIQUE CODE START 
       prepareConnection(connection, GET); 
       connection.connect(); 
       // UNIQUE CODE END 

       BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream())); 
       while ((line = br.readLine()) != null) { 
        jsonString.append(line); 
       } 
       br.close(); 
       connection.disconnect(); 
       keepGoing = false; 
      } catch (Exception e) { 
       log.warn("Try #{}. Error getting from API: {}", tries, e.getMessage()); 
       log.warn("Pausing for 1 second then trying again..."); 
       try { 
        TimeUnit.SECONDS.sleep(1); 
       } catch (InterruptedException f) { 
        log.warn("Sleeping has been interrupted: {}", f.getMessage()); 
       } 
      } 
     } 
     return jsonString.toString(); 
    } 

    /** 
    * Prepares the HTTP Url connection depending on whether this is a POST or GET call 
    * 
    * @param connection the connection to prepare 
    * @param method  whether the call is a POST or GET call 
    */ 
    private void prepareConnection(HttpURLConnection connection, String method) { 
     String charset = "UTF-8"; 
     try { 
      connection.setRequestMethod(method); 
      if (method.equals(GET)) { 
       connection.setRequestProperty("Accept-Charset", charset); 
      } else if (method.equals(POST)) { 
       connection.setDoInput(true); 
       connection.setDoOutput(true); 
       connection.setRequestProperty("Content-Type", "application/json; charset=" + charset); 
      } 
      connection.setRequestProperty("Accept", "application/json"); 
      connection.setRequestProperty("Authorization", "Bearer " + apiKey); 
     } catch (Exception e) { 
      log.error("Error preparing HTTP URL connection: {}", e.getMessage()); 
      throw new RuntimeException(e.getMessage()); 
     } 
    } 

나는 여기에 코드 중복을 절약하기 위해 "실행 방법의 주위에"패턴을 사용할 수 : 고유 섹션의 시작 및 종료 어디 보여주는 의견이 방법의 고유 한 부분을 감싸거야? 그렇다면 누군가이 코드를 사용하도록이 코드를 리팩터링하는 방법을 알아낼 수 있습니다. 이것이 잘못된 길이라면 누군가가 현명한 대안을 제시 할 수 있을까요?

답변

5

특수 작업자에게 "고유"코드를 추출하여 수행 할 수 있습니다.

public String apiPost(String urlString, String payload) { 
    return commonMethod(urlString, payload, (connection) -> { 
     // UNIQUE CODE START 
     prepareConnection(connection, POST); 
     OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream(), "UTF-8"); 
     writer.write(payload); 
     writer.close(); 
     // UNIQUE CODE END 
    }); 
} 

interface ConnectionWorker { 
    void run(HttpURLConnection connection) throws IOException; 
} 

public String commonMethod(String urlString, String payload, ConnectionWorker worker) { 
    boolean keepGoing = true; 
    int tries = 0; 

    String line; 
    StringBuilder jsonString = new StringBuilder(); 

    log.debug("Making API Call: {}", urlString); 

    while (keepGoing && tries < MAX) { 
     tries++; 
     try { 
      URL url = new URL(urlString); 

      HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 

      worker.run(connection); 

      BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream())); 
      while ((line = br.readLine()) != null) { 
       jsonString.append(line); 
      } 
      br.close(); 
      connection.disconnect(); 
      keepGoing = false; 
     } catch (Exception e) { 
      log.warn("Try #{}. Error posting: {}", tries, e.getMessage()); 
      log.warn("Pausing for 1 second then trying again..."); 
      try { 
       TimeUnit.SECONDS.sleep(1); 
      } catch (InterruptedException f) { 
       log.warn("Sleeping has been interrupted: {}", f.getMessage()); 
      } 
     } 
    } 
    return jsonString.toString(); 
} 

UPDATE : 더 구체적으로 예를 들어, 당신은 람다 표현식을 사용할 수

return commonMethod(urlString, payload, new ConnectionWorker() { 
     @Override 
     public void run(HttpURLConnection connection) throws IOException { 
      // UNIQUE CODE START 
      CallHandler.this.prepareConnection(connection, POST); 
      OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream(), "UTF-8"); 
      writer.write(payload); 
      writer.close(); 
      // UNIQUE CODE END 
     } 
    }); 
+0

감사에 대한 : 혹시 java 8과 람다를 사용할 수없는 경우, 당신은 익명의 클래스를 생성 항상을 전환 할 수 있습니다 회신 @Andremoniy 나는 그것을 이해하기 시작하고 있다고 생각한다. (비록 나는 Lambda에 대해 약간의 독서를해야한다.) 어쨌든 람다 없이는 Google App Engine 용으로 개발 중이며 Java 8을 지원하지 않는다고 생각합니다. S – SBmore

+0

@SBmore 제 편집을보고 익명 클래스를 사용할 수 있습니다 – Andremoniy

+0

감사합니다. 너무 많은 @Areremoniy, 이것은 크게 도움이되었고 나는 많은 것을 배웠다. – SBmore