2016-08-02 1 views
4

У меня есть класс, который имеет два метода, которые содержат много дубликатов, но бит, который является уникальным, находится в середине всего. Из моих исследований, я думаю, что я должен делать шаблон «Выполнять вокруг метода», но я не могу найти ресурс, который я могу отслеживать, поскольку все они, похоже, используют код, который я не могу реплицировать.Избегайте дублирования кода, когда уникальная часть находится в цикле/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: В случае, если вы не можете использовать java 8 и лямбда, вы всегда можете переключиться на создание анонимный класс:

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

Спасибо за Ответ @Andremoniy Я думаю, что я начинаю это понимать (хотя мне нужно кое-что прочитать на лямбда). Есть ли все равно сделать это без Lambda, поскольку я разрабатываю для Google App Engine, и я не думаю, что он поддерживает Java 8: S – SBmore

+0

@SBmore Да, конечно, посмотрите мое редактирование, вы можете использовать анонимный класс – Andremoniy

+0

Спасибо так много @Andremoniy, это очень помогло, и я многому научился. – SBmore

Смежные вопросы