2012-03-13 10 views
6

Tengo varios métodos que hacen lo mismo hasta el momento, al interconectarse con la base de datos MySQL, guardar o cargar un tipo diferente de parámetro. Actualmente, tengo un método diferente para cada tipo. ¿Cómo puedo combinar estos métodos para que sean compatibles con diferentes tipos?Métodos de refactorización que usan el mismo código pero tipos diferentes

A continuación se muestra un ejemplo de dos métodos que son muy similares pero utilizan diferentes tipos:

public static void saveLongArray(Connection con, int playerID, String tableName, String fieldName, long[] array, long[] originalArray) { 
    try { 
     for (int i = 0; i < array.length; i++) { 
      // Check for change before running query 
      if (array[i] != originalArray[i]) { 
       if (array[i] != 0 && array[i] != -1) { 
        PreparedStatement updateQuery = con.prepareStatement("REPLACE INTO `" + tableName + "` (`player_id`, `index`, `" + fieldName + "`) VALUES(?, ?, ?)"); 
        updateQuery.setInt(1, playerID); 
        updateQuery.setInt(2, i); 
        updateQuery.setLong(3, array[i]); 
        updateQuery.execute(); 
       } else { 
        PreparedStatement deleteQuery = con.prepareStatement("DELETE FROM `" + tableName + "` WHERE `player_id` = ? AND `index` = ?"); 
        deleteQuery.setInt(1, playerID); 
        deleteQuery.setInt(2, i); 
        deleteQuery.execute(); 
       } 

       originalArray[i] = array[i]; 
      } 
     } 
    } catch (SQLException ex) { 
     Logger.getLogger(PlayerSaveHandler.class.getName()).log(Level.SEVERE, "SQL Exception while saving a long array!", ex); 
    } 
} 

public static void saveIntArray(Connection con, int playerID, String tableName, String fieldName, int[] array, int[] originalArray) { 
    try { 
     for (int i = 0; i < array.length; i++) { 
      // Check for change before running query 
      if (array[i] != originalArray[i]) { 
       if (array[i] != 0 && array[i] != -1) { 
        PreparedStatement updateQuery = con.prepareStatement("REPLACE INTO `" + tableName + "` (`player_id`, `index`, `" + fieldName + "`) VALUES(?, ?, ?)"); 
        updateQuery.setInt(1, playerID); 
        updateQuery.setInt(2, i); 
        updateQuery.setInt(3, array[i]); 
        updateQuery.execute(); 
       } else { 
        PreparedStatement deleteQuery = con.prepareStatement("DELETE FROM `" + tableName + "` WHERE `player_id` = ? AND `index` = ?"); 
        deleteQuery.setInt(1, playerID); 
        deleteQuery.setInt(2, i); 
        deleteQuery.execute(); 
       } 

       originalArray[i] = array[i]; 
      } 
     } 
    } catch (SQLException ex) { 
     Logger.getLogger(PlayerSaveHandler.class.getName()).log(Level.SEVERE, "SQL Exception while saving an int array!", ex); 
    } 
} 

nota en ese ejemplo los tipos son tanto numérica. En un caso donde los tipos son completamente diferentes (por ejemplo, int y String), ¿qué podría hacer para evitar tener métodos near-duplicate?

Respuesta

12

Puede aplicar Estrategia patrón aquí.

interface TypeDependentBehavior<T> { 
    void setFieldValue(PreparedStatement st, T value); 
} 

interface StringBehavior extends TypeDependentBehavior<String> { 
    void setFieldValue(PreparedStatement st, String value) { 
    st.setString(3, value); 
    } 
}  

interface IntBehavior extends TypeDependentBehavior<Integer> { 
    void setFieldValue(PreparedStatement st, Integer value) { 
    st.setInt(3, value); 
    } 
} 

.....

public static void saveArray<T>(Connection con, int playerID, String tableName, String fieldName, T[] array, T[] originalArray, TypeDependentBehavior<T> behavior) { 
try { 
     for (int i = 0; i < array.length; i++) { 
      // Check for change before running query 
      if (array[i] != originalArray[i]) { 
       if (array[i] != 0 && array[i] != -1) { 
        PreparedStatement updateQuery = con.prepareStatement("REPLACE INTO `" + tableName + "` (`player_id`, `index`, `" + fieldName + "`) VALUES(?, ?, ?)"); 
        updateQuery.setInt(1, playerID); 
        updateQuery.setInt(2, i); 
        behavior.setFieldValue(updateQuery, array[i]); 
        updateQuery.execute(); 
       } else { 
        PreparedStatement deleteQuery = con.prepareStatement("DELETE FROM `" + tableName + "` WHERE `player_id` = ? AND `index` = ?"); 
        deleteQuery.setInt(1, playerID); 
        deleteQuery.setInt(2, i); 
        deleteQuery.execute(); 
       } 

       originalArray[i] = array[i]; 
      } 
     } 
    } catch (SQLException ex) { 
     Logger.getLogger(PlayerSaveHandler.class.getName()).log(Level.SEVERE, "SQL Exception while saving an int array!", ex); 
    } 
} 
+0

He estado investigando este patrón de diseño, pero nunca habría pensado en usarlo en este caso. ¡Gracias! – jSherz

+0

Lo único que agregaría aquí es que, dado que las matrices ahora transportarán objetos en lugar de primitivas, deberían compararse usando 'equals()' (por ej. '! Array [i] .equals (originalArray [i])' o 'compareTo()'. Además, parece que se supone que las matrices solo contienen tipos numéricos, por lo que no necesitamos un comportamiento para String, y el argumento de tipo probablemente debería ser '' solo para estar seguros – jpm

+0

¿Es una buena idea agregar en Java la implementación en interfaces? ¿No sería mejor que una clase abstracta? – flurdy

3

Me limitaría a utilizar long[] en lugar de int[]. La diferencia de memoria es muy pequeña en comparación con el costo de usar JDBC.

Si necesita manejar String puede usar un tipo de objeto.

public static void saveArray(Connection con, int playerID, String tableName, 
    String fieldName, Object[] array, Object[] originalArray) { 

Si desea un método para long[] y Object[] puede utilizar el método Array.getLength() y Array.get() acceder a todos los tipos de matriz genérica. Esto podría agregar más complejidad de la que ahorra.

+2

Esto no responde a la pregunta de "¿y si' 'int' y string'?" – ggrigery

2

Puede utilizar genéricos para que, por ejemplo

void doSomething(int[] array) { 
    for (int i = 0; i < array.length; i++) 
     System.out.println(array[i]); 
} 

void doSomething(long[] array) { 
    for (int i = 0; i < array.length; i++) 
     System.out.println(array[i]); 
} 

se puede generalizar en

<T> void doSomething(T[] array) { 
    for (int i = 0; i < array.length; i++) 
     System.out.println(array[i]); 
} 

Ahora se puede llamar

int[] array1 = new int[] { 1, 2, 3 }; 
doSomething(array1); 

long[] array2 = new long[] { 1L, 2L, 3L }; 
doSomething(array2); 

String[] array3 = new String[] { "one", "two", "three" }; 
doSomething(array3); 

Pero usted debe revisar su implementación del método y asegúrese de que funcionará con cualquier tipo de matriz, especialmente la declaración SQL.

1

¿Qué pasa si descubres tu funcionalidad comparativa y has reducido tus métodos al nivel más detallado? Por ejemplo:

public static void update(Connection con, int playerID, String tableName, String fieldName, String value) { 
    // update query logic here 
} 

Y lo mismo para delete(). No hay ninguna razón para pasar los valores "nuevo" y "original" en esta función y hacer la comparación dentro. Sugiero recorrer las matrices, comparar y llamar a update() o delete() en función de sus necesidades. Para tratar con diferentes tipos de datos, siempre pasaría el valor String de lo que desea en la base de datos.

0

con tipos similares, se podría crear un envoltorio - un método que toma como argumento una int[], genera un long[] de los valores pasados ​​y llama a la variante del procedimiento que se lleva long[] como argumento para llevar a cabo el trabajo real. Tiene algunos gastos generales, pero suponiendo que sus matrices no tienen millones de entradas, es insignificante en comparación con el costo de comunicación con la base de datos.

Con tipos completamente diferentes, puede intentar usar Object[] (o tal vez de alguna manera usar genéricos), pero habría algunos inconvenientes. Debería usar un marcador de borrado diferente en lugar de 0 o -1 (null parece ser la opción más obvia).El problema más grande es establecer parámetros en PreparedStatement ya que necesitan ser llamados diferentes métodos, pero que podría generar toda la cadena de consulta manualmente, usando métodos toString() los objetos proporcionados en lugar de los parámetros de ajuste con setInt() etc.

Cuestiones relacionadas