Refactoring methods that use the same code but different types

后端 未结 5 1782
情深已故
情深已故 2020-12-31 14:22

I have several methods that do the same thing yet, when interfacing with the MySQL database, save or load a different type of parameter. Currently, I have a different method

相关标签:
5条回答
  • 2020-12-31 14:55

    You can use generics for that, for example

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

    can be generalized into

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

    Now you can call

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

    But you should check your method implementation and make sure that it will still work with any array type, especially the SQL statement.

    0 讨论(0)
  • 2020-12-31 14:57

    You can apply the Strategy pattern here.

    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 讨论(0)
  • 2020-12-31 15:00

    What if you broke out your comparative functionality and had your methods down to the most granular level? For example:

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

    And the same for delete(). There is no reason to pass both the "new" and "original" values into this function and do the compare inside. I suggest looping through the arrays, comparing, and calling either update() or delete() based on your needs. To deal with different data types, I would always pass in the String value of what you want in the database.

    0 讨论(0)
  • 2020-12-31 15:15

    I would just use long[] instead of int[]. The memory difference is very small compared with the cost of using JDBC.

    If you need to handle String you can use an object type.

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

    If you want one method for long[] and Object[] you can use the Array.getLength() and Array.get() method to access all array types generically. This could add more complexity than it saves.

    0 讨论(0)
  • 2020-12-31 15:20

    With similar types, you could create a wrapper - a method which takes as an argument an int[], generates a long[] from the values passed and calls the method variant which takes long[] as argument to perform the actual work. It has some overhead, but assuming your arrays are not millions of entries long, it's negligible compared to the cost of communication with the database.

    With completely different types, you could try using Object[] (or maybe somehow use generics), but there would be some pitfalls. You would need to use a different deletion marker instead of 0 or -1 (null seems the obvious choice). The bigger issue is setting parameters in PreparedStatement since different methods need to be called but you could generate the whole query string manually, using the provided objects' toString() methods instead of setting parameters with setInt() etc.

    0 讨论(0)
提交回复
热议问题