#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 на этапе заполнения решения Кочарда