Tolmács tervezési minta Java-ban

1. Áttekintés

Ebben az oktatóanyagban bemutatjuk az egyik viselkedési GoF tervezési mintát - az Tolmácsot.

Először áttekintést adunk a céljáról és elmagyarázzuk a problémát, amelyet megpróbál megoldani.

Ezután megnézzük az Tolmács UML-diagramját és a gyakorlati példa megvalósítását.

2. Tolmács tervezési minta

Röviden, a minta meghatározza egy adott nyelv nyelvtanát objektum-orientált módon, amelyet maga a tolmács értékelhet.

Ezt szem előtt tartva, technikailag megépíthetjük az egyedi reguláris kifejezésünket, egy egyedi DSL-tolmácsunkat, vagy elemezhetjük az emberi nyelvek bármelyikét, épít absztrakt szintaxisfákat, majd futtassa az értelmezést.

Ez csak néhány a lehetséges felhasználási esetek közül, de ha elgondolkodunk egy ideig, még több felhasználást találhatunk, például az IDE -inkben, mivel folyamatosan értelmezik az általunk írt kódot, és ezáltal ellátják velünk felbecsülhetetlen tippeket.

Az értelmező mintát általában akkor kell használni, ha a nyelvtan viszonylag egyszerű.

Ellenkező esetben nehéz lesz fenntartani.

3. UML diagram

A fenti ábra két fő entitást mutat: a Kontextus és a Kifejezés.

Bármelyik nyelvet ki kell fejezni valamilyen módon, és a szavaknak (kifejezéseknek) az adott kontextus alapján lesz valamilyen jelentése.

Absztrakt kifejezés meghatároz egy absztrakt módszert, amely a kontextust veszi átparaméterként. Ennek köszönhetően minden kifejezés hatással lesz a kontextusra, változtassa meg az állapotát, vagy vagy folytassa az értelmezést, vagy adja vissza magát az eredményt.

Ezért a kontextus a feldolgozás globális állapotának birtokosa lesz, és az egész értelmezési folyamat során újra felhasználásra kerül.

Tehát mi a különbség a TerminalExpression és NonTerminalExpression?

A NonTerminalExpression lehet egy vagy több más AbsztraktKifejezések társul hozzá, ezért rekurzívan értelmezhető. A végén, az értelmezési folyamatnak be kell fejeződnie egy TerminalExpression ez visszaadja az eredményt.

Érdemes ezt megjegyezni NonTerminalExpression egy összetett.

Végül az ügyfél szerepe egy már létrehozott létrehozása vagy felhasználása absztrakt szintaxisfa, ami nem más, mint a a létrehozott nyelven definiált mondat.

4. Végrehajtás

A minta működés közbeni megjelenítéséhez objektum-orientált módon felépítünk egy egyszerű SQL-szerű szintaxist, amelyet aztán értelmezünk, és visszaküldjük az eredményt.

Először meghatározzuk Válasszon, és Hol kifejezéseket, készítsen szintaxisfát az ügyfél osztályában, és futtassa az értelmezést.

A Kifejezés az interfész értelmezési metódusa lesz:

Listaértelmezés (Context ctx);

Ezután meghatározzuk az első kifejezést, a Válassza a lehetőséget osztály:

class Select megvalósítja a Expression {private String oszlopot; privát Feladó tól; // konstruktor @Override public List interpret (Kontextus ctx) {ctx.setColumn (oszlop); visszatérés innen.értelmez (ctx); }}

Megkapja a kiválasztandó oszlop nevét és egy másik konkrétumot Kifejezés típusú Tól től mint paraméterek a konstruktorban.

Vegye figyelembe, hogy a felülbírált értelmez() módszer a kontextus állapotát állítja be, és az értelmezést tovább adja egy másik kifejezésbe a kontextussal együtt.

Így látjuk, hogy ez a NonTerminalExpression.

Egy másik kifejezés a Tól től osztály:

class Feladatokból Expression {private String table; privát Hol hol; // konstruktorok @Override public List interpret (Kontextus ctx) {ctx.setTable (tábla); if (ahol == null) {return ctx.search (); } return where.interpret (ctx); }}

Most az SQL-ben a ahol a záradék opcionális, ezért ez az osztály vagy terminál, vagy nem terminális kifejezés.

Ha a felhasználó úgy dönt, hogy nem használ egy hol záradékot, akkor a Tól től kifejezés azt a ctx.search () hívja és adja vissza az eredményt. Ellenkező esetben tovább fogják értelmezni.

A Hol kifejezés ismét módosítja a kontextust a szükséges szűrő beállításával, és az értelmezést keresési hívással fejezi be:

osztály Ahol megvalósítja az Expression {private Predicate szűrőt; // konstruktor @Override public List interpret (Kontextus ctx) {ctx.setFilter (szűrő); return ctx.search (); }}

Például a Kontextus osztály az adatbázis tábláját utánzó adatokat tárolja.

Ne feledje, hogy három kulcsmezője van, amelyeket a Kifejezés és a keresési módszer:

osztály Kontextus {privát statikus térkép táblák = new HashMap (); statikus {List list = new ArrayList (); list.add (új sor ("John", "Doe")); list.add (új sor ("Jan", "Kowalski")); list.add (új sor ("Dominic", "Doom")); táblák.put ("emberek", lista); } privát String asztal; privát húr oszlop; privát predikátum whereFilter; // ... Lista keresése () {Lista eredménye = táblák.entrySet () .stream () .filter (bejegyzés -> entry.getKey (). EqualsIgnoreCase (táblázat)) .flatMap (bejegyzés -> Stream.of (bejegyzés .getValue ())) .flatMap (Collection :: stream) .map (Row :: toString) .flatMap (columnMapper) .filter (whereFilter) .collect (Collectors.toList ()); egyértelmű(); visszatérési eredmény; }}

A keresés befejezése után a kontextus kitisztítja önmagát, így az oszlop, a táblázat és a szűrő alapértelmezett értékre van állítva.

Így mindegyik értelmezés nem befolyásolja a másikat.

5. Tesztelés

Tesztelés céljából vessünk egy pillantást a InterpreterDemo osztály:

public class InterpreterDemo {public static void main (String [] args) {Expression query = new Select ("név", új Feladó ("emberek")); Context ctx = new Context (); Lista eredménye = query.interpret (ctx); System.out.println (eredmény); Expression query2 = new Select ("*", new From ("people")); Lista eredménye2 = lekérdezés2.értelmez (ctx); System.out.println (eredmény2); Kifejezés lekérdezése3 = új Kiválasztás ("név", új Feladó ("emberek", új Hol (név -> név.toLowerCase (). IndulWith ("d")))); Lista eredménye3 = lekérdezés3.értelmez (ctx); System.out.println (eredmény3); }}

Először létrehozunk egy szintaxisfát létrehozott kifejezésekkel, inicializáljuk a kontextust, majd lefuttatjuk az értelmezést. A kontextust újrafelhasználják, de mint fentebb bemutattuk, minden keresési hívás után megtisztul.

A program futtatásával a kimenetnek a következőknek kell lennie:

[John, Jan, Dominic] [John Doe, Jan Kowalski, Dominic Doom] [Dominic]

6. Hátrányok

Amikor a nyelvtan összetettebbé válik, nehezebb fenntartani.

A bemutatott példában látható. Meglehetősen könnyű lenne hozzáadni egy másik kifejezést, például Határ, mégsem lesz túl könnyű fenntartani, ha úgy döntünk, hogy tovább bővítjük az összes többi kifejezéssel.

7. Következtetés

A tolmács tervezési mintája remek a viszonylag egyszerű nyelvtani értelmezéshez, amelynek nem kell sokat fejlődnie és kiterjednie.

A fenti példában megmutattuk, hogy objektum-orientált módon lehet SQL-szerű lekérdezést felépíteni a tolmácsminta segítségével.

Végül megtalálhatja ezt a mintahasználatot a JDK-ban, különösen a java.util.Minta, java.text.Format vagy java.text.Normalizer.

Szokás szerint a teljes kód elérhető a Github projekten.


$config[zx-auto] not found$config[zx-overlay] not found