2009-05-21 1 views
0

У меня есть 9 разных грамматик. Один из них будет загружен в зависимости от того, что первая строка txt находится в файле, который он разбор.Как превратить условную цепочку в более быстрый уродливый код?

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

Действительно, скорость определенно моя цель здесь, но я знаю, что это уродливый код.

Щас код выглядит примерно так:

sin.mark(0) 
site = findsite(txt) 
sin.reset() 

if (site == "site1") { 
    loadlexer1; 
    loadparser1; 
} else if (site == "site2") { 
    loadlexer2; 
    loadparser2; 
} 
................. 
} else if (site == "site8") { 
    loadparser8; 
    loadparser8; 
} 

findsite(txt) { 
    ................... 
    if line.indexOf("site1-identifier") { 
    site = site1; 
    } else if(line.indexOf("site2-identifier") { 
    site = site2; 
    } else if(line.indexOf("site3-identifier") { 
    site = site3; 
    } 
    ......................... 
    } else if(line.indexOf("site8-identifier") { 
    site = site8; 
    } 
} 

некоторых пояснения

1) да, я действительно есть 9 различных грамматик я построил с ANTLR так что они будут иметь свой собственный лексер/parser objs.

2) да, на данный момент мы сравниваем строки и obivously, которые заменяются каким-то целым отображением. Я также рассматривал возможность прикрепления идентификаторов сайтов к одному регулярному выражению, однако я не верю, что это ускорит что-то.

3) да, это псевдокод, так что я бы не слишком разборчивы в семантике здесь ..

4) kdgregory является правильным, отмечая, что я не могу создать один экземпляр пары лексического анализатора/парсера

Мне нравится идея хеш-кода, чтобы код выглядел немного лучше, но я не думаю, что это будет скорость меня.

+0

Собственно, это не выглядит так плохо. И это одна из причин, по которой они построили такую ​​команду if-else, как раз для этой ситуации. Что касается скорости, она должна быть коротко замкнута как можно быстрее. –

+0

Пожалуйста, скажите, что вы не устанавливаете 'site' в строку маркера и используете сравнения строк, чтобы проверить это. Это действительно ints или что-то, не так ли? –

+0

Кроме того, я думаю, вы имеете в виду if (line.indexOf (...)> = 0)) – Mark

ответ

2

Использование полиморфизма почти гарантированно будет быстрее, чем манипуляции с строкой, и будет проверено на правильность во время компиляции. Есть site действительно строка? Если это так, FindSite следует называть GetSiteName. Я бы ожидал, что FindSite вернет объект Site, который знает соответствующий лексер и парсер.

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

+0

Плюс, это поможет коду не нарушать Open/Closed. Если вам нужно добавить сайт 9, вы не будете редактировать файл, содержащий код о том, что делает сайт 1. Подобная настройка является ошибкой копирования-вставки, ожидающей своего появления. –

1

Что-то вроде:

Map<String,LexerParserTuple> lptmap = new HashMap<String,LexerParserTuple>(); 
lpt=lptmap.get(site) 
lpt.loadlexer() 
lpt.loadparser() 

в сочетании с некоторой регулярным выражением магией, а не String.indexOf(), чтобы захватить имена сайтов, необходимо резко очистить код.

+0

Вы должны объяснить, как lptmap заселяется. В качестве бонуса покажите, как java.util.ServiceLoader можно использовать для динамического добавления новых лексеров/парсеров, просто отбросив JAR на путь к классам. – erickson

+0

Спасибо erickson, к сожалению, это немного отличается от моих непосредственных навыков Java :) – lostlogic

7

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

Map<String,Lexer> lexerMap = new HashMap<String,Lexer>(); 
lexerMap.put("source1", new Lexer01()); 
lexerMap.put("source2", new Lexer02()); 
// and so on 

После того как вы обрабатываете строку, которая идентифицирует лексер использовать, вы бы получить он со Карты выглядит так:

String grammarId = // read it from a file, whatever 
Lexer myLexer = lexerMap.get(grammarId); 

В вашем примере кода есть несколько причуд. Во-первых, вызовы indexOf() указывают, что у вас нет отдельной строки, и Map не будет выглядеть внутри строки.Поэтому вам нужно каким-то образом извлечь фактический ключ из любой строки, которую вы читаете.

Во-вторых, лексеры и парсеры обычно поддерживают состояние, поэтому вы не сможете создать один экземпляр и повторно использовать его. Это означает, что вам нужно создать заводский класс и сохранить его на карте (это шаблон Abstract Factory).

Если вы ожидаете, что у вас будет много разных лексеров/парсеров, тогда имеет смысл использовать ориентированный на карту подход. Для небольшого числа цепочка if-else, вероятно, лучше всего подходит, правильно инкапсулирована (это шаблон Factory Method).

+0

Со ссылками, это отличный ответ. – Mark

0

я бы изменить тип findsite вернуть тип сайта (супер класс), а затем рычаги воздействия полиморфизма ... Это должно быть быстрее, чем со строками ...

вам нужны отдельные лексических ли?

0

Используйте карту, чтобы настроить сайт для загрузки стратегической структуры. Затем требуется простой поиск на основе «сайта», и вы выполняете соответствующую стратегию. То же самое можно сделать для findSite().

1

Replace Conditional With Polymorphism

Для полумеры, для findsite(), вы можете просто создать HashMap, чтобы получить Вас от идентификатора сайта на сайт. Альтернатива очистки будет просто вернуть строку сайта, таким образом:

String findsite(txt) { 
    ................... 
    if line.indexOf("site1-identifier") 
    return site1; 
    if(line.indexOf("site2-identifier") 
    return site2; 
    if(line.indexOf("site3-identifier") 
    return site3; 
... 
} 

Использование IndexOf(), таким образом, не очень выразительной; Я бы использовал equals() или contains().

0

Может иметь карту идентификаторов против сайтов, а затем просто перебирать записи карты.

// define this as a static somewhere ... build from a properties file 
Map<String,String> m = new HashMap<String,String>(){{ 
    put("site1-identifier","site2"); 
    put("site2-identifier","site2"); 
}} 

// in your method 
for(Map.Entry<String,String> entry : m.entries()){ 
    if(line.contains(entry.getKey())){ 
     return line.getValue(); 
    } 
} 

уборщик: да быстрее: не знаю ... должно быть достаточно быстро

0

Вы можете использовать отражение возможно

char site = line.charAt(4); 
Method lexerMethod = this.getClass().getMethod("loadLexer" + site, *parameters types here*) 
Method parserMethod = this.getClass().getMethod("loadparser" + site, *parameters types here*) 

lexerMethod.invoke(this, *parameters here*); 
parserMethod.invoke(this, *parameters here*); 
1

Я думал о выводе лексер/парсер нерест в сеп. классов, а затем создавая их, как только я получу матч

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

Я предполагаю, что некоторые бенчмаркинг в порядке

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

Возможно, если вы беспокоитесь, что у вас есть метод "kilometric", вы можете его реорганизовать в различные функции с помощью extract method.

Самое главное - иметь первое решение, выполняющее работу, даже если оно работает медленно, и как только вы его работаете, проецируйте его и определите точки, в которых производительность может быть улучшена.Помните, "Rules of optimization"

1

Предположим, ваш код неэффективен.

Потребуется больше времени, чем (скажем) 1% времени для фактического анализа ввода?

Если нет, у вас есть большая рыба для жарки.

0

Я не знаю о Java, но некоторые языки позволяют переключаться на строки.

switch(site) 
{ 
    case "site1": loadlexer1; loadparser1; break; 
    case "site2": loadlexer2; loadparser2; break; 
    ... 
} 

Что касается секундного бита, используйте регулярное выражение, чтобы извлечь идентификатор и включить его. Возможно, вам лучше использовать enum.

+0

Java не разрешала включать строки во время этого ответа, но поддержка была добавлена ​​в Java 1.7. – Jolta