===== 8 - Návrhové vzory Interpreter, Visitor ===== ==== Možné řešení z minulého cvičení ==== [[https://gitlab.fel.cvut.cz/B181_B6B36OMO/seminar/tree/master/cv7_solution|]] ===== Teorie ===== ==== Vzor Interpreter ==== === Problém === Pro určitý (formální) jazyk chceme vytvořit reprezentaci pomocí objektů v paměti, abychom mohli pracovat s výrazy v tomto jazyce a vyhodnocovat je. === Řešení === Vzor interpreter popisuje jak definovat gramatiku pro jednoduchý jazyk, reprezentovat výrazy v tomto jazyce a interpretovat je. Hierarchická reprezentace výrazu obsahuje dva základní druhy prvků: * **primitivní výraz**, který je kompletní sám o sobě a ke svému vyhodnocení nepotřebuje žádné další výrazy * **složený výraz**, který se skládá z libovolných dalších výrazů (primitivních či složených) a tyto výrazy potřebuje ke svému vyhodnocení Podobná hierarchie je reprezentována návrhovým vzorem **Composite**, který má obecnější použití než jen pro reprezentaci výrazů. {{:courses:a7b36omo:labs:interpreter.png?500|}} ==== Vzor Visitor ==== === Problém === Chceme vytvořit operaci pracující s elementy objektové struktury. Může se jednat o mnoho samostatných a nesouvisejících operací. Chceme však zabránit znepřehlednění kódu objektů těmito operacemi a chceme mít možnost definovat nové operace beze změny tříd se kterými pracují. === Řešení === Vzor visitor primárně abstrahuje funkcionalitu, která může být aplikována na celou hierarchii objektů. Triviálním řešením by bylo vytvoření třídy, do které umístíme samostatnou metodu pro každou podtřídu hierarchie objektů. Veřejná bude pouze metoda přijímající kořenovou třídu hierarchie a dále se pomocí ''if'' podmínek a ověření typu parametru rozhodne, kterou z následujících metod zavolá. Efektivnější řešení využívá takzvaný //double dispatch//. Java však podporuje pouze //single dispatch//, při kterém je volání metody závislé na názvu metody a identifikaci příjemce. Návrhový vzor visitor toto rozšiřuje o identifikaci odesílatele. První směrování požadavku je od objektu Visitor ke konkrétnímu elementu, který odpovědí zpět objektu Visitor souhlasí s návštěvou a identifikuje typ třídy. {{:courses:a7b36omo:labs:visitor.png?500|}} ===== Příklady k řešení ===== Stáhněte si z repository základ cvičení 8: [[https://gitlab.fel.cvut.cz/B171_B6B36OMO/seminar/tree/master/cv8_assignment|]] Přečtěte si o [[https://github.com/google/guava/wiki/ImmutableCollectionsExplained|Immutable Collections]] ==== Implementace ve cvičení 8 bude v následujících krocích ==== **1.** Do připraveného programu doimplementujte výrazy (operátory), použijte vzor interpreter: * IntList: konstantní seznam, * VarList: proměnná, jméno proměnné identifikuje seznam definovaný v kontextu pro vyhodnocení výrazu, * Remove: odstraní všechny výskyty elementu v podvýrazu, př.: R([1, 2, 3, 2], 2) -> [1, 3], zachovává původní pořadí, * Concatenate: spojí dva seznamy, př.:C([1,2,3,4],[5,6,7]) -> [1,2,3,4,5,6,7], * Unique: pro každý prvek vrátí jen jeho první výskyt, př.: U ([3, 2, 1, 2, 2, 1]) -> [3, 2, 1], zachovává pořadí,\\ \\ * Vysledkem vyhodnocení bude: ImmutableList. **2.** Přidejte podporu pro vzor visitor a naimplementujte třídu PrintListExpressionVisitor. * Použijte prefixovou notaci. Pro názvy neterminalních operátorů stačí první písmeno jejich názvu. * Pozor na závorky. Př.: spojení seznamu x a [1,2,3] vytisknete jako C (x, [1, 2, 3]). **3.** Naimplementujte visitor (SimplifyListExpressionVisitor), který bude schopen symbolicky zjednodušit výrazy podle následujícího pravidla: * Pokud jsou všichni potomci konstantními seznamy, nahradí rodičovský uzel konstantním seznamem s výsledkem vyhodnocení. Operátor instanceof je přípustný. Nemodifikujte původní vyraz. Minimalizujte opakování kódu. === Užitečné tipy: === Převod ImmutableList -> ArrayList: List list = new ArrayList<>(immutableList); Převod List -> ImmutableList: ImmutableList immutableList = ImmutableList.copyOf(list); Odstranění všech výskytů prvků element ze seznamu: list.removeAll(Collections.singleton(element)); Seznamy typu ''List'' můžete tisknout přímo pomocí ''System.out.print()''.