Interpreteerimisest üldisemalt
Siin aines käsitleme interpretaatorid eelkõige selleks, et programmidest paremini aru saada ja seega ehitada oma programmeerimisoksus tugevamal põhjal. Samas tasub rõhutada, et avaldised ei ole ainsad asjad maailmas, mida võiks "interpreteerida". Käsude täitmine on üks võimalus eraldada äriloogika (mida peab tegema?) ja selle implementatsioonist. Võtame siin lihtne näide läbi, kus ühtlasi saab illustreerida ka ANTLRi mõned võimalused. Kood asub paketis interdemo.
Nagu ikka selliste eluliste ülesannete puhul on meil vaja kedagi aidata. Seekord on hädas testimisega sõbralik spämmija Stefan, kes tahab kõikidele oma nimekirjas olevatele inimestele sõnumeid saata. Tal on mõnede jaoks telefoninumber ja mõnedel ainult e-mail. Sisendfail näeb tal välja järgmine:
Vesal Vojdani: vesal.vojdani@spammail.com Varmo Vene: +371 666 6666
Kuna päris rämpsposti saatmine ei ole võib-olla Ülikoolis õpetatava näidena kõige parem mõtte, siis peab siin kutsuma klassi Relay meetodid sendMail ja sendSMS. Nad trükivad lihtsalt midagi ekraanile spämmi saatmise asemel.
Otse ANTLRiga
Spämmija Stefan on tubli AKT tudeng ja oskab isegi kasutada ANTLRi kuulajad, et väga kiiresti sellise suurepärase lahenduse kirjutada. Grammatika on defineeritud failis interdemo/Spammer.g4 ja spämmi saatmise kood on klassi SpamAst meetodis sendSpam:
SpammerBaseListener listener = new SpammerBaseListener() { @Override public void exitEmail(EmailContext ctx) { Relay.sendMail(ctx.EMAIL().getText(), ctx.NAME().getText(), MSG); } @Override public void exitPhone(PhoneContext ctx) { String numStr = ctx.NUMBER().getText(); long number = Long.valueOf(numStr.replaceAll("[\\+ -]", "")); Relay.sendSMS(number, ctx.NAME().getText(), MSG); } };
Stefan kasutab siin ANTLRi listener liidest ja seetõttu sai väga kiiresti selle asja valmis, aga selle koodi testimine on üks igavene nuhtlus. Üks variant on meie Relay klassi mockida ja seeläbi kontrollida, et kutsutakse õigeid asju, aga palju lihtsam on tegelikult siin kasutada interpretaatorit!
Sinu ülesanne: interpretaatori abil
Interpretaatori mustri peamine mõtte on sellise vaheandmestruktuuri loomine, mille sisse saame kergesti vaadata ja seega kontrollida, et plaanitud tegevused on õiged. Meil on paketis spammerast kahte tüüpi käske:
- MailCmd (konstruktor võtab e-mail aadressi)
- SmsCmd (konstruktor võtab telefoninumbri)
Nad on siis mõlemad RelayCommands alamklassid, mistõttu interpretaator ainult kutsub nende send meetodi:
public static void interpret(List<RelayCommands> commands) { for (RelayCommands cmd : commands) cmd.send(); }
Sinu ülesanne on siis implementeerida klassi SpamAst meetodit createAst, mis loob sellise RelayCommandide list, mille täitmisel me saaks sama tulemuse kui Stefani lahendus! Sellise listi puhul on aga palju lihtsam testida, et kõik soovitud tegevused on nagu oodatud. Üks lihtne test ongi klassis SpamAstTest, millega saad proovida, et Sul on spämmeri loogika õigesti implementeeritud.