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

我有几种方法可以做同样的事情,当与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),我可以做些什么来避免接近重复的方法?

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

 interface TypeDependentBehavior { void setFieldValue(PreparedStatement st, T value); } interface StringBehavior extends TypeDependentBehavior { void setFieldValue(PreparedStatement st, String value) { st.setString(3, value); } } interface IntBehavior extends TypeDependentBehavior { void setFieldValue(PreparedStatement st, Integer value) { st.setInt(3, value); } } 

…..

 public static void saveArray(Connection con, int playerID, String tableName, String fieldName, T[] array, T[] originalArray, TypeDependentBehavior 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); } } 

我只想使用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()方法来一般地访问所有数组类型。 这可能会增加比节省更多的复杂性。

例如,您可以使用generics

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

可以概括为

  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语句。

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

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

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

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

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