Как мне избежать повторения?

1

Я делаю учебник на Java, и я всегда читаю, что я должен стараться не повторяться, и я заметил, что это очень повторяемо; Поэтому, если кто-нибудь может дать мне несколько советов, чтобы сделать его менее повторяющимся или каким-то образом лучше, он будет очень полезен. Спасибо;) (Это не часть учебника, я сделал это просто для удовольствия из-за того, что я изучаю в науке в школе)

  1. Файл Run.java:

    package scientificFormula;
    
    public class Run {
    
        public static void main(String[] args) {
            Formula formula = new Formula();
    
            formula.compound1 = args[0];
            formula.compound2 = args[1];
    
            String theFormula = formula.createFormula();
            System.out.println("Molecule: " + args[0] + " " + args[1] + " = "
                    + theFormula);
        }
    
    }
    
  2. Файл Formula.java:

    package scientificFormula;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class Formula {
        String compound1;
        String compound2;
        static private Map<String, String> map = new HashMap<String, String>();
    
        static private void initiateIons() {
            // 1+
            map.put("Hydrogen", "H^1+");
            map.put("Lithium", "Li^1+");
            map.put("Sodium", "Na^1+");
            map.put("Potassium", "K^1+");
            map.put("Rubidium", "Rb^1+");
            // 2+
            map.put("Magnesium", "Mg^2+");
            map.put("Calcium", "Ca^2+");
            map.put("Strontium", "Sr^2+");
            // 3+
            map.put("Aluminium", "Al^3+");
            // 3-
            map.put("Nitrogem", "N^-3");
            map.put("Phosphorus", "P^-3");
            // 2-
            map.put("Oxygen", "O^-2");
            map.put("Sulfur", "S^-2");
            map.put("Selenium", "Se^-2");
            // 1-
            map.put("Fluorine", "F^-1");
            map.put("Chlorine", "Cl^-1");
            map.put("Bromine", "Br^-1");
            map.put("Iodine", "I^-1");
        }
    
        String createFormula() {
            initiateIons();
    
            // Example1: Input = Calcium Iodine:
            // 2x + -1y = 0
            // x = 1 and y = 2
            // Output = CaI2
            //
            // Example2: Input = Sulfur Iodine
            // Output = Molecule: Sulfur Iodine = SI2
    
            String symbol1 = map.get(compound1);
            String symbol2 = map.get(compound2);
    
            int charge1 = Integer.parseInt(symbol1.replace("+", "").substring(
                    symbol1.length() - 2));
            int charge2 = Integer.parseInt(symbol2.replace("+", "").substring(
                    symbol2.length() - 2));
    
            String letter1 = null;
            String letter2 = null;
    
            if (symbol1.length() == 5) {
                letter1 = symbol1.substring(0, 2);
            } else if (symbol1.length() == 4) {
                letter1 = symbol1.substring(0, 1);
            }
            if (symbol2.length() == 5) {
                letter2 = symbol2.substring(0, 2);
            } else if (symbol2.length() == 4) {
                letter2 = symbol2.substring(0, 1);
            }
    
            int possitive1 = (int) Math.sqrt(charge1 * charge1);
            int possitive2 = (int) Math.sqrt(charge2 * charge2);
    
            if ((possitive1 == 1) & (possitive2 == 1)) {
                return letter1 + letter2;
            } else if (possitive1 == 1) {
                return letter1 + possitive2 + letter2;
            } else if (possitive2 == 1) {
                return letter1 + letter2 + possitive1;
            }
            if (possitive1 == 0) {
                possitive1 = -(charge1);
            }
    
            if (possitive2 == 0) {
                possitive2 = -(charge2);
            }
    
            return letter1 + possitive2 + letter2 + possitive1;
        }
    }
    
  • 0
    Какой кусок ты находишь повторяющимся?
  • 1
    @ElliottFrisch части внизу - под createFormula() (немного скрыто - требуется прокрутка)
Показать ещё 8 комментариев
Теги:

5 ответов

3
Лучший ответ

Я настоятельно рекомендую прочитать чистый код книги, который в основном касается рефакторинга.

Дублирование кода является лишь одной (важной) проблемой при запуске рефакторинга (также называемом DRY - Do not Repeat Yourself). Есть много других принципов, и я попытаюсь описать некоторые из них, которые я считаю наиболее важными:

Одним из важных "эмпирических правил" является принцип SRP: Single Responsibility, в котором говорится, что каждый класс должен иметь только одну ответственность, и если мы применяем ту же идею к методам - каждый метод должен делать только одно! Это может показаться очень строгим, но когда вы начнете его применять, ваш код станет более понятным для чтения и упрощения его использования.

Другой использует значащие имена (классы/методы/переменные):

return letter1 + possitive2 + letter2; // you probably meant positive with one 's' (typo!)

может означать что-то для вас - но это не будет означать много другого читателя - теперь, конечно, вы можете решить это, добавив комментарии к коду, но это исправление проблемы вместо ее решения. Кроме того, комментарии к коду становятся устаревшими - либо становятся неуместными, либо даже хуже - могут ввести читателя в заблуждение, когда код изменится, а комментарий - нет.

И последнее (на данный момент), сохраняйте четкий порядок выполнения, позволяйте взять фрагмент кода, который вы разместили, и улучшить его:

    String symbol1 = map.get(compound1);
    String symbol2 = map.get(compound2);

    int charge1 = Integer.parseInt(symbol1.replace("+", "").substring(
            symbol1.length() - 2));
    int charge2 = Integer.parseInt(symbol2.replace("+", "").substring(
            symbol2.length() - 2));

    String letter1 = null;
    String letter2 = null;

    if (symbol1.length() == 5) {
        letter1 = symbol1.substring(0, 2);
    } else if (symbol1.length() == 4) {
        letter1 = symbol1.substring(0, 1);
    }
    if (symbol2.length() == 5) {
        letter2 = symbol2.substring(0, 2);
    } else if (symbol2.length() == 4) {
        letter2 = symbol2.substring(0, 1);
    }

    int possitive1 = (int) Math.sqrt(charge1 * charge1);
    int possitive2 = (int) Math.sqrt(charge2 * charge2);

Как видим, положительный зависит от заряда, который зависит от символа, который зависит от соединения. И тотально не связано с ним: буква зависит от символа, который зависит от состава.

пусть разделить его на отдельные методы:

int getPositive(String compound) { // I have no idea what "positive", "symbol" and compound represent, consider better names please
    String symbol = map.get(compound);
    int charge = Integer.parseInt(symbol.replace("+", "").substring(
                symbol.length() - 2));
    return (int) Math.sqrt(charge2 * charge2);
}

И теперь мы можем применить то же самое к getLetter(String compound) {...} и т.д.

  • 0
    Огромное спасибо. Наверное, лучший ответ здесь. Я думал о том, чтобы поместить что-то в разные методы, но когда я попробовал это, были ошибки в локальных переменных и прочее, поэтому я просто решил не делать этого. Я продолжу свой урок, так как это было что-то забавное, и я попытаюсь купить эту книгу - хехе описание выглядит интересно. (Я очень новичок в Java. Началось около 4 недель назад.)
  • 1
    @ gogobebe2 в твою пользу (помимо того, что ты только начал) Я должен сказать, что у меня сложилось впечатление, что ты очень организован и последовательн. Эти два качества будут вам полезны, если вы решите погрузиться в мир программирования!
Показать ещё 1 комментарий
2

Я бы выбрал часть этого разбора в свой класс, возможно, вы даже сможете разгрузить его там, когда вы создадите больше функциональности.

public class Symbol {
    final int charge;
    final String letter;
    public Symbol(String str) {
        int sepIndex = str.indexOf('^');
        if(sepIndex != -1) {
            letter = str.substring(0, sepIndex);
            charge = Integer.parseInt(str.substring(sepIndex+1).replace("+", ""));
        } else {
            throw new IllegalArgumentException(str + " isnt a valid Symbol, no ^ found");
        }
    }
}

public class Formula {
    String compound1;
    String compound2;
    static private Map<String, String> map = new HashMap<String, String>();

    // make this a static block so its only called once.
    static {
        // 1+
        map.put("Hydrogen", "H^1+");
        map.put("Lithium", "Li^1+");
        map.put("Sodium", "Na^1+");
        map.put("Potassium", "K^1+");
        map.put("Rubidium", "Rb^1+");
        // 2+
        map.put("Magnesium", "Mg^2+");
        map.put("Calcium", "Ca^2+");
        map.put("Strontium", "Sr^2+");
        // 3+
        map.put("Aluminium", "Al^3+");
        // 3-
        map.put("Nitrogem", "N^-3");
        map.put("Phosphorus", "P^-3");
        // 2-
        map.put("Oxygen", "O^-2");
        map.put("Sulfur", "S^-2");
        map.put("Selenium", "Se^-2");
        // 1-
        map.put("Fluorine", "F^-1");
        map.put("Chlorine", "Cl^-1");
        map.put("Bromine", "Br^-1");
        map.put("Iodine", "I^-1");
    }
    String createFormula() {

        // Example1: Input = Calcium Iodine:
        // 2x + -1y = 0
        // x = 1 and y = 2
        // Output = CaI2
        //
        // Example2: Input = Sulfur Iodine
        // Output = Molecule: Sulfur Iodine = SI2

        Symbol symbol1 = new Symbol(map.get(compound1));
        Symbol symbol2 = new Symbol(map.get(compound2));

        int possitive1 = Math.abs(symbol1.charge); // sqrt(a*a) == abs(a)
        int possitive2 = Math.abs(symbol1.charge);

        if ((possitive1 == 1) & (possitive2 == 1)) {
            return symbol1.letter + symbol1.letter;
        } else if (possitive1 == 1) {
            return symbol1.letter + possitive2 + symbol2.letter;
        } else if (possitive2 == 1) {
            return symbol1.letter + symbol2.letter + possitive1;
        }

        // dead code, if positive1 is 0 then setting it to -0 does nothing
        /*if (possitive1 == 0) {
            possitive1 = -(symbol1.charge);
        }
        if (possitive2 == 0) {
            possitive2 = -(symbol2.charge);
        }*/

        return symbol1.letter + possitive2 + symbol2.letter + possitive1;
    }
}
  • 0
    Большое спасибо. Сообщество stackoverflow настолько удивительно, насколько щедро со временем они! : D
  • 0
    Я понятия не имею, почему я сделал, если (possitive2 == 0) LOL
1

Ну, сначала позвольте изменить свой код так, чтобы все... 1 переменные были вместе. Судя по вашему соглашению об именах, вы используете letter1 для вычисления символа1, символа1 для вычисления charge1 и т.д. Я просто собираюсь сосредоточиться на createFormula(), так как часть, которую вы хотите уменьшить по размеру.

String createFormula() {
    initiateIons();

    //Calculate symbol1, charge1, letter1, possitive1
    String symbol1 = map.get(compound1);
    int charge1 = Integer.parseInt(symbol1.replace("+", "").substring(
            symbol1.length() - 2));
    String letter1 = null;
    if (symbol1.length() == 5) {
        letter1 = symbol1.substring(0, 2);
    } else if (symbol1.length() == 4) {
        letter1 = symbol1.substring(0, 1);
    }
    int possitive1 = (int) Math.sqrt(charge1 * charge1);

    //calculate symbol2, charge2, letter2, possitive2
    String symbol2 = map.get(compound2);
    int charge2 = Integer.parseInt(symbol2.replace("+", "").substring(
            symbol2.length() - 2));
    String letter2 = null;
    if (symbol2.length() == 5) {
        letter2 = symbol2.substring(0, 2);
    } else if (symbol2.length() == 4) {
        letter2 = symbol2.substring(0, 1);
    }
    int possitive2 = (int) Math.sqrt(charge2 * charge2);

    //Returns
    if ((possitive1 == 1) & (possitive2 == 1)) {
        return letter1 + letter2;
    } else if (possitive1 == 1) {
        return letter1 + possitive2 + letter2;
    } else if (possitive2 == 1) {
        return letter1 + letter2 + possitive1;
    }
    if (possitive1 == 0) {
        possitive1 = -(charge1);
    }

    if (possitive2 == 0) {
        possitive2 = -(charge2);
    }

    return letter1 + possitive2 + letter2 + possitive1;
}

Я согласен, шаг вычисления кажется излишним. Было бы замечательно иметь функцию, которая вычисляет те и возвращает кортеж из них, но (насколько я знаю) Java еще не имеет кортежей. Мы можем сделать строковый массив, хотя и проанализировать ints обратно из строк. Здесь менее избыточный пересмотр кода.

String[] calculatePieces(String compound){
    String symbol = map.get(compound);
    int charge = Integer.parseInt(symbol.replace("+", "").substring(
            symbol.length() - 2));
    String letter = null;
    if (symbol.length() == 5) {
        letter = symbol1.substring(0, 2);
    } else if (symbol1.length() == 4) {
        letter = symbol1.substring(0, 1);
    }
    int possitive = (int) Math.sqrt(charge * charge);
    pieces = new String[4];
    pieces[0] = symbol;
    pieces[1] = charge + "";
    pieces[2] = letter;
    pieces[3] = possitive + "";
    return pieces;
}

String createFormula() {
    initiateIons();

    String[] pieces1 = calculatePieces(compound1);
    int charge1 = Integer.parseInt(pieces1[1]);
    int possitive1 = Integer.parseInt(pieces1[3]);
    String[] pieces2 = calculatePieces(compound2);
    int charge2 = Integer.parseInt(pieces2[1]);
    int possitive2 = Integer.parseInt(pieces2[3]);

    //Returns
    if ((possitive1 == 1) & (possitive2 == 1)) {
        return pieces1[2] + pieces2[2];
    } else if (possitive1 == 1) {
        return pieces1[2] + possitive2 + pieces2[2];
    } else if (possitive2 == 1) {
        return pieces1[2] + pieces2[2] + possitive1;
    }
    if (possitive1 == 0) {
        possitive1 = -(charge1);
    }

    if (possitive2 == 0) {
        possitive2 = -(charge2);
    }

    return pieces1[2] + possitive2 + pieces2[2] + possitive1;
}

Это немного лучше, но ограничение Java при возврате одного объекта ограничивает то, насколько это можно получить. Способ сделать его еще более чистым - сделать объект-оболочку, который в основном действует как кортеж (string, int, string, int), но если вам нужно, чтобы это было быстрым, а не тем, как идти.

  • 2
    Очень хороший ответ, большое спасибо за то, что нашли время для своего дня.
1

Я считаю, что это эквивалентно вашему опубликованному коду -

private static String checkCompound(String symbol) {
  if (symbol.length() == 5) {
    return symbol.substring(0, 2);
  } else if (symbol.length() == 4) {
    return symbol.substring(0, 1);
  }
  return "";
}

затем

String letter1 = checkCompound(symbol1);
String letter2 = checkCompound(symbol2);

if (charge1 > 0) {
  if (charge2 > 0) {
    return letter1 + letter2;
  }
  return letter1 + charge2 + letter2;
} else if (charge2 > 0) {
  return letter1 + letter2 + charge1;
}

return letter1 + charge2 + letter2 + charge1;

Наконец, это

if (possitive1 == 0) {
  possitive1 = -(charge1);
}

был удален, потому что он -0 равен 0.

  • 0
    @ gogobebe2 Хорошо. int possitive1 = (int) Math.sqrt(charge1 * charge1) сообщает нам, что possitive1 == обвинение1. Почему? Что такое квадратный корень из 2 * 2 , 3 * 3 , n * n ? Вы ожидали, что это будет абсолютное значение?
  • 0
    @ gogobebe2 Почему - (0) будет положительным? Кроме того, для чего был Math.sqrt(charge1 * charge1) ?
1

Первый метод:

getCharge(String symbol){
       return Integer.parseInt(symbol.replace("+", "").substring(symbol.length() - 2));
}

Второй метод:

getLetter(String symbol){
    if (symbol.length() == 5) {
        return symbol.substring(0, 2);
    } else if (symbol.length() == 4) {
        return symbol.substring(0, 1);
    } 
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню