избегайте дублирования кода

#java #code-duplication

#java #дублирование кода

Вопрос:

рассмотрим следующий код:

 if (matcher1.find()) {
   String str = line.substring(matcher1.start() 7,matcher1.end()-1);
   /* 7 and -1 indicate the prefix and suffix of the matcher... */    
   method1(str);
}
if (matcher2.find()) {
   String str = line.substring(matcher2.start() 8,matcher2.end()-1);
   method2(str);
}
...
  

У меня есть n сопоставителей, все сопоставители независимы (если один из них имеет значение true, это ничего не говорит об остальных …), для каждого сопоставителя, который имеет значение true, я вызываю другой метод для содержимого, которому он соответствует.

вопрос: Мне не нравится ни дублирование кода, ни «магические числа» здесь, но мне интересно, есть ли лучший способ сделать это …? (может быть, шаблон посетителя?) есть предложения?

Комментарии:

1. Если они независимы, вы должны быть в состоянии создать большое регулярное выражение и использовать download.oracle.com/javase/tutorial/essential/regex /… выполните итерацию по подстрокам.

2. @Helper: 404 в вашей ссылке «кому» связано с .html

3. download.oracle.com/javase/tutorial/essential/regex/groups.html

Ответ №1:

Создайте абстрактный класс и добавьте смещение в подкласс (с обработкой строк тоже … в зависимости от ваших требований).

Затем поместите их в список и обработайте список.

Вот пример процессора abstract:

 public abstract class AbsractProcessor {

    public void find(Pattern pattern, String line) {
        Matcher matcher = p.matcher(line);
        if (matcher.find()) {
            process(line.substring(matcher.start()   getStartOffset(), matcher.end() - getEndOffset()));
        }
    }

    protected abstract int getStartOffset();

    protected abstract int getEndOffset();

    protected abstract void process(String str);

}
  

Комментарии:

1. Это кажется элегантным, я все еще думаю, не многовато ли это для моего случая (немного похоже на поимку бабочки из пушки) 1 в любом случае, за элегантность.

2. Это кажется слишком большим, потому что Java слишком многословна, было бы более элегантно с языком с функциональным вкусом, таким как Scala или Python.

3. Но одно из моих золотых правил таково: НИКОГДА, НИКОГДА НЕ дублируйте какой-либо код … иначе вы исправите одну и ту же ошибку несколько раз (или забудете …). В этом сила абстракции… и, ИМХО, именно это делает вас хорошим программистом. Кстати, примите ответ, если вас это устраивает 😉

Ответ №2:

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

Например, если ваше регулярное выражение является foo.*bar и вас не интересует foo или bar , создайте регулярное выражение foo(.*)bar . Затем всегда берите группу 1 из Matcher .

Тогда ваш код будет выглядеть следующим образом:

 method1(matcher1.group(1));
method2(matcher2.group(2));
...
  

Еще одним шагом было бы заменить ваши методы классами, реализующими подобное:

 public interface MatchingMethod {
  String getRegex();
  void apply(String result);
}
  

Затем вы можете легко автоматизировать задачу:

 for (MatchingMethod mm : getAllMatchingMethods()) {
  Pattern p = Pattern.compile(mm.getRegex());
  Matcher m = p.matcher(input);
  while (m.find()) {
    mm.apply(m.group(1));
}
  

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

Комментарии:

1. 1 за использование групп захвата, что немного упрощает ситуацию.

Ответ №3:

Вы могли бы сделать это немного короче, но у меня вопрос в том, действительно ли это стоит затраченных усилий:

 private String getStringFromMatcher(Matcher matcher, int magicNumber) {
   return line.subString(matcher.start()   magicNumber, matcher.end() - 1 )
}

if (matcher1.find()) {
method1(getStringFromMatcher(matcher1, 7);
}

if (matcher2.find()) {
method2.(getStringFromMatcher(mather2, 8);
}
  

Ответ №4:

используйте решение Кочарда в сочетании с factory (оператор switch) со всеми методами MethodX. итак, вы можете назвать это следующим образом:

 Factory.CallMethodX(myEnum.MethodX, str)
  

вы можете назначить MyEnum.Методx на этапе заполнения решения Кочарда