重构使用相同代码但不同类型的方法

时间:2012-03-13 16:55:35

标签: java refactoring

我有几种方法可以做同样的事情,当与MySQL数据库连接时,保存或加载不同类型的参数。目前,我对每种类型都有不同的方法。如何组合这些方法以便它们支持不同的类型?

下面是两个非常相似但使用不同类型的方法的示例:

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

请注意,在该示例中,类型都是数字。在类型完全不同的情况下(例如int和String),我可以做些什么来避免接近重复的方法?

5 个答案:

答案 0 :(得分:13)

您可以在此处应用策略模式。

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

答案 1 :(得分:3)

我只会使用long[]代替int[]。与使用JDBC的成本相比,内存差异非常小。

如果需要处理String,可以使用对象类型。

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

如果您需要long[]Object[]的一种方法,则可以使用Array.getLength()Array.get()方法一般性地访问所有数组类型。 这可能会增加比节省更多的复杂性。

答案 2 :(得分:2)

您可以使用泛型,例如

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

可以概括为

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

现在你可以打电话了

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

但是你应该检查你的方法实现,并确保它仍然适用于任何数组类型,尤其是SQL语句。

答案 3 :(得分:1)

如果您突破了比较功能并将方法降至最细微的水平,该怎么办?例如:

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

delete()也一样。没有理由将“new”和“original”值都传递给这个函数并在里面进行比较。我建议循环遍历数组,比较并根据您的需要调用update()delete()。为了处理不同的数据类型,我总是会在数据库中传递你想要的String值。

答案 4 :(得分:0)

使用类似的类型,您可以创建一个包装器 - 一个以int[]为参数的方法,从传递的值生成long[]并调用方法变量long[]作为执行实际工作的论据。它有一些开销,但假设您的数组长度不是数百万条,与数据库通信的成本相比,它可以忽略不计。

使用完全不同的类型,您可以尝试使用Object[](或者可能以某种方式使用泛型),但会有一些陷阱。您需要使用不同的删除标记而不是0或-1(null似乎是显而易见的选择)。更大的问题是在PreparedStatement中设置参数,因为需要调用不同的方法,但您可以使用提供的对象toString()方法手动生成整个查询字符串,而不是使用setInt()设置参数等