Рефакторинг методов, использующих один и тот же код, но разных типов - PullRequest
8 голосов
/ 13 марта 2012

У меня есть несколько методов, которые делают одно и то же, при взаимодействии с базой данных 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 ]

13 голосов
/ 13 марта 2012

Здесь вы можете применить шаблон Стратегия .

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);
    }
}
3 голосов
/ 13 марта 2012

Я бы просто использовал long[] вместо int[]. Разница в памяти очень мала по сравнению со стоимостью использования JDBC.

Если вам нужно обработать строку, вы можете использовать тип объекта.

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

Если вам нужен один метод для long[] и Object[], вы можете использовать метод Array.getLength() и Array.get() для общего доступа ко всем типам массивов. Это может добавить больше сложности, чем экономит.

2 голосов
/ 13 марта 2012

Для этого вы можете использовать дженерики, например,

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.

1 голос
/ 13 марта 2012

Что если вы продемонстрировали свою сравнительную функциональность и опустили свои методы до самого детального уровня?Например:

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

И то же самое для delete().Нет причин передавать в эту функцию как «новые», так и «оригинальные» значения и выполнять сравнение внутри.Я предлагаю перебирать массивы, сравнивать и вызывать либо update(), либо delete() в зависимости от ваших потребностей.Чтобы иметь дело с различными типами данных, я бы всегда передавал значение String того, что вы хотите в базе данных.

0 голосов
/ 13 марта 2012

С подобными типами вы можете создать оболочку - метод, который принимает в качестве аргумента int[], генерирует long[] из переданных значений и вызывает вариант метода, который принимает long[] в качестве аргумента для выполнения фактическогоРабота.У него есть некоторые накладные расходы, но если предположить, что ваши массивы не состоят из миллионов записей, это незначительно по сравнению со стоимостью связи с базой данных.

С совершенно разными типами вы можете попробовать использовать Object[] (или, может быть, каким-то образомиспользовать дженерики), но будут некоторые подводные камни.Вам нужно будет использовать другой маркер удаления вместо 0 или -1 (null кажется очевидным выбором).Более сложная проблема заключается в установке параметров в PreparedStatement, поскольку необходимо вызывать разные методы, но вы можете сгенерировать всю строку запроса вручную, используя методы toString() предоставленных объектов вместо установки параметров с помощью setInt() и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...