2012-03-13 9 views
6

Ho diversi metodi che fanno ancora la stessa cosa, quando si interfaccia con il database MySQL, salvare o caricare un diverso tipo di parametro. Attualmente, ho un metodo diverso per ogni tipo. Come posso combinare questi metodi in modo che supportino tipi diversi?Metodi di refactoring che utilizzano lo stesso codice ma tipi diversi

seguito è un esempio di due metodi che sono ancora molto simili utilizzano diversi tipi:

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 in quell'esempio i tipi sono entrambi numerico. In un caso in cui i tipi sono completamente diversi (ad esempio int e String), cosa posso fare per evitare metodi quasi duplicati?

risposta

12

È possibile applicare strategia modello qui.

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

Ho esaminato questo modello di progettazione ma non avrei mai pensato di usarlo in questo caso. Grazie! – jSherz

+0

L'unica cosa che aggiungerei qui è che, poiché gli array porteranno ora oggetti anziché primitive, dovrebbero essere confrontati usando 'equals()' (ad esempio '! Array [i] .equals (originalArray [i])' o 'compareTo()'. Inoltre, si presume che gli array contengano solo tipi numerici, quindi non abbiamo bisogno di un comportamento per String, e l'argomento type dovrebbe probabilmente essere '' solo per sicurezza – jpm

+0

L'aggiunta di implementazione nelle interfacce è una buona idea in Java? Non sarebbe meglio come classe astratta? – flurdy

3

Vorrei solo utilizzare long[] anziché int[]. La differenza di memoria è molto piccola rispetto al costo dell'utilizzo di JDBC.

Se è necessario gestire String, è possibile utilizzare un tipo di oggetto.

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

Se si desidera un metodo per long[] e Object[] è possibile utilizzare il metodo Array.getLength() e Array.get() per accedere a tutti i tipi di array generico. Questo potrebbe aggiungere più complessità di quanto non risparmia.

+2

Ciò non rispondere alla sua domanda di "che cosa se' 'int' e STRING'?" – ggrigery

2

È possibile utilizzare farmaci generici per questo, ad esempio

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

può essere generalizzato in

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

Ora è possibile chiamare

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

Ma si dovrebbe verificare l'implementazione metodo e assicurati che funzioni ancora con qualsiasi tipo di array, in particolare con l'istruzione SQL.

1

Cosa succederebbe se si interrompesse la funzionalità comparativa e i metodi fossero ridotti al livello più granulare? Ad esempio:

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

E lo stesso per delete(). Non c'è motivo per passare entrambi i valori "nuovo" e "originale" in questa funzione e fare il confronto all'interno. Suggerisco di eseguire il looping degli array, confrontare e chiamare update() o delete() in base alle proprie esigenze. Per gestire diversi tipi di dati, passerei sempre il valore String di ciò che si desidera nel database.

0

Con tipi simili, si potrebbe creare un involucro - un metodo che prende come argomento un int[], genera un long[] dai valori passati e chiama la variante metodo che prende long[] come argomento per eseguire il lavoro effettivo. Ha un sovraccarico, ma supponendo che gli array non siano milioni di voci lunghe, è trascurabile rispetto al costo della comunicazione con il database.

Con tipi completamente diversi, è possibile provare a utilizzare Object[] (o forse usare in qualche modo i generici), ma ci sarebbero alcune insidie. Dovresti utilizzare un indicatore di eliminazione diverso da 0 o -1 (null sembra la scelta più ovvia).Il problema più grande è l'impostazione dei parametri in PreparedStatement poiché metodi diversi hanno bisogno di essere chiamato, ma si potrebbe generare l'intera stringa di query manualmente, utilizzando toString() metodi degli oggetti forniti invece di impostazione dei parametri con setInt() ecc

Problemi correlati