繁体   English   中英

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

[英]Refactoring methods that use the same code but different types

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

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

您可以为此使用泛型,例如

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语句)一起使用。

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

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

delete()相同。 没有理由将“新”和“原始”值都传递到此函数中并在内部进行比较。 我建议根据需要循环遍历数组,比较并调用update()delete() 为了处理不同的数据类型,我将始终在数据库中传递所需的String值。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM