Besøgendes designmønster i Java

1. Oversigt

I denne vejledning introducerer vi et af de adfærdsmæssige GoF-designmønstre - Besøgende.

Først forklarer vi dets formål og problemet, det forsøger at løse.

Dernæst ser vi på Visitors UML-diagram og implementering af det praktiske eksempel.

2. Besøgende designmønster

Formålet med et besøgermønster er at definere en ny operation uden at introducere ændringer til en eksisterende objektstruktur.

Forestil dig, at vi har en sammensatteobjekt, der består af komponenter. Objektets struktur er fast - vi kan enten ikke ændre det, eller vi planlægger ikke at tilføje nye typer af elementer til strukturen.

Hvordan kunne vi nu tilføje ny funktionalitet til vores kode uden ændring af eksisterende klasser?

Besøgendes designmønster kan være et svar. Kort fortalt, vi bliver nødt til at gøre er at tilføje en funktion, der accepterer besøgsklassen til hvert element i strukturen.

På den måde vil vores komponenter tillade den besøgende implementering at "besøge" dem og udføre enhver nødvendig handling på dette element.

Med andre ord udtrækker vi algoritmen, der vil blive anvendt på objektstrukturen fra klasserne.

Følgelig, vi gør god brug af Open / Closed-princippet da vi ikke ændrer koden, men vi stadig kan udvide funktionaliteten ved at levere en ny Besøgende implementering.

3. UML-diagram

På UML-diagrammet ovenfor har vi to implementeringshierarkier, specialiserede besøgende og konkrete elementer.

Først og fremmest bruger klienten en besøgendeimplementering og anvender den på objektstrukturen. Det sammensatte objekt gentager sig over dets komponenter og anvender den besøgende på hver af dem.

Nu er det især relevant konkrete elementer (ConcreteElementA og BetonElementB) accepterer en Besøgende, blot lade det besøg dem.

Endelig er denne metode den samme for alle elementer i strukturen, den udfører dobbelt forsendelse med at passere sig selv (via det her nøgleord) til den besøgendes besøgsmetode.

4. Implementering

Vores eksempel vil være skik Dokument objekt, der består af JSON og XML konkrete elementer; elementerne har en fælles abstrakt superklasse, Element.

Det Dokument klasse:

public class Document udvider Element {List elements = new ArrayList (); // ... @Override public void accept (Visitor v) {for (Element e: this.elements) {e.accept (v); }}}

Det Element klasse har en abstrakt metode, der accepterer Besøgende grænseflade:

offentlig abstrakt ugyldig accept (besøgende v);

Navngiv det derfor, når du opretter det nye element JsonElement, bliver vi nødt til at give implementeringen af ​​denne metode.

På grund af besøgermønsterets art vil implementeringen imidlertid være den samme, så det vil i de fleste tilfælde kræve, at vi kopierer og indsætter kedelpladekoden fra et andet allerede eksisterende element:

offentlig klasse JsonElement udvider Element {// ... public void accept (Visitor v) {v.visit (this); }}

Da vores elementer tillader besøg af enhver besøgende, lad os sige, at vi vil behandle vores Dokument elementer, men hver af dem på en anden måde afhængigt af klassetype.

Derfor vil vores besøgende have en separat metode til den givne type:

offentlig klasse ElementVisitor implementerer besøgende {@Override offentligt ugyldigt besøg (XmlElement xe) {System.out.println ("behandler et XML-element med uuid:" + xe.uuid); } @ Override offentligt ugyldigt besøg (JsonElement je) {System.out.println ("behandler et JSON-element med uuid:" + je.uuid); }}

Her implementerer vores konkrete besøgende to metoder, svarende til en pr. Hver type af Element.

Dette giver os adgang til det bestemte objekt i strukturen, som vi kan udføre nødvendige handlinger på.

5. Testning

Til testformål skal vi se på VisitorDemoklasse:

offentlig klasse VisitorDemo {public static void main (String [] args) {Visitor v = new ElementVisitor (); Dokument d = nyt dokument (genererUuid ()); d.elements.add (nyt JsonElement (generereUuid ())); d.elements.add (nyt JsonElement (generereUuid ())); d.elements.add (nyt XmlElement (createUuid ())); d.accept (v); } // ...}

Først opretter vi en ElementBesøgende, den indeholder den algoritme, vi vil anvende på vores elementer.

Derefter opretter vi vores Dokument med de rette komponenter og anvend den besøgende, som vil blive accepteret af hvert element i en objektstruktur.

Outputtet ville være sådan:

behandling af et JSON-element med uuid: fdbc75d0-5067-49df-9567-239f38f01b04 behandling af et JSON-element med uuid: 81e6c856-ddaf-43d5-aec5-8ef977d3745e bearbejdning af et XML-element med uuid: 091bfcb8-2c68-491a-931

Det viser, at besøgende har besøgt hvert element i vores struktur, afhængigt af Element type sendte den behandlingen til passende metode og kunne hente dataene fra hvert underliggende objekt.

6. Ulemper

Som hvert designmønster har selv besøgende sine ulemper, især dets brug gør det vanskeligere at vedligeholde koden, hvis vi har brug for at tilføje nye elementer til objektets struktur.

For eksempel hvis vi tilføjer nyt YamlElement, så er vi nødt til at opdatere alle eksisterende besøgende med den nye metode, der ønskes til behandling af dette element. Efter dette yderligere, hvis vi har ti eller flere konkrete besøgende, kan det være besværligt at opdatere dem alle.

Bortset fra dette bliver forretningslogikken relateret til et bestemt objekt, når man bruger dette mønster, spredt over alle besøgendeimplementeringer.

7. Konklusion

Besøgende mønster er fantastisk at adskille algoritmen fra de klasser, som den fungerer på. Derudover gør det lettere at tilføje ny operation bare ved at give en ny implementering af besøgende.

Desuden er vi ikke afhængige af komponentgrænseflader, og hvis de er forskellige, er det fint, da vi har en separat algoritme til behandling pr. Konkret element.

Desuden kan besøgende til sidst samle data baseret på det element, den krydser.

For at se en mere specialiseret version af Visitor-designmønsteret, tjek gæstemønsteret i Java NIO - brugen af ​​mønsteret i JDK.

Som sædvanlig er den komplette kode tilgængelig på Github-projektet.