Automatisk generering av byggemønsteret med FreeBuilder

1. Oversikt

I denne veiledningen bruker vi FreeBuilder-biblioteket til å generere byggeklasser i Java.

2. Builder Design Pattern

Builder er en av de mest brukte Creation Design Patterns på objektorienterte språk. Den abstraherer instantiering av et komplekst domeneobjekt og gir et flytende API for å opprette en forekomst. Det hjelper derved å opprettholde et kortfattet domenelag.

Til tross for nytten er en byggherre generelt kompleks å implementere, spesielt i Java. Selv enklere verdiobjekter krever mye kjelekode.

3. Builderimplementering i Java

Før vi fortsetter med FreeBuilder, la oss implementere en kokeplatebygger for vår Ansatt klasse:

offentlig klasse Ansatt {privat slutt Strengnavn; privat sluttalder; privat slutt Stringavdeling; privat ansatt (strengnavn, alder, strengavdeling) {dette.navn = navn; this.age = alder; dette. avdeling = avdeling; }}

Og en indre Bygger klasse:

offentlig statisk klasse Builder {privat strengnavn; privat alder; privat strengavdeling; public Builder setName (strengnavn) {this.name = name; returner dette; } public Builder setAge (int age) {this.age = age; returner dette; } public Builder setDepartment (strengavdeling) {this.department = avdeling; returner dette; } offentlig ansattbygging () {returner ny ansatt (navn, alder, avdeling); }}

Følgelig kan vi nå bruke byggherren til å instantiere Ansatt gjenstand:

Employee.Builder emplBuilder = ny Employee.Builder (); Ansatt ansatt = emplBuilder .setName ("baeldung") .setAge (12) .setDepartment ("Builder Pattern") .build ();

Som vist ovenfor, mye kokerplatekode er nødvendig for å implementere en byggeklasse.

I de senere avsnittene vil vi se hvordan FreeBuilder umiddelbart kan forenkle denne implementeringen.

4. Maven avhengighet

For å legge til FreeBuilder-biblioteket, legger vi til FreeBuilder Maven-avhengighet i vår pom.xml:

 org.inferred freebuilder 2.4.1 

5. FreeBuilder Kommentar

5.1. Generere en byggmester

FreeBuilder er et open source-bibliotek som hjelper utviklere med å unngå kjeleplatekoden mens de implementerer byggeklasser. Den bruker behandling av merknader i Java for å generere en konkret implementering av byggemønsteret.

Vi vil kommentere vår Ansatt klasse fra tidligere seksjon med @FreeBuilderog se hvordan det automatisk genererer byggeklassen:

@FreeBuilder offentlig grensesnitt Ansatt {Strengnavn (); int alder (); Strengavdeling (); class Builder utvider Employee_Builder {}}

Det er viktig å påpeke det Ansatt er nå en grensesnitti stedet for en POJO-klasse. Videre inneholder den alle attributtene til en Ansatt objekt som metoder.

Før vi fortsetter å bruke denne byggmesteren, må vi konfigurere IDEene våre for å unngå kompileringsproblemer. Siden FreeBuilder genererer automatisk Employee_Builder klasse under kompilering, IDE klager vanligvis på ClassNotFoundException på linje nummer 8.

For å unngå slike problemer, vi må aktivere merknader i IntelliJ eller Eclipse. Og mens vi gjør det, bruker vi FreeBuilders merkeprosessor org.inferred.freebuilder.processor.Processor. I tillegg skal katalogen som brukes til å generere disse kildefilene være merket som Generated Sources Root.

Alternativt vi kan også utføre mvn installere å bygge prosjektet og generere nødvendige byggeklasser.

Til slutt har vi samlet prosjektet vårt og kan nå bruke Ansatt.Bygger klasse:

Employee.Builder builder = ny Employee.Builder (); Ansatt ansatt = byggmester.navn ("baeldung") .alder (10) .avdeling ("Byggmønster") .bygg ();

Alt i alt er det to hovedforskjeller mellom dette og byggeklassen vi så tidligere. Først, vi må sette verdien for alle attributtene til Ansatt klasse. Ellers kaster det en IllegalStateException.

Vi får se hvordan FreeBuilder håndterer valgfrie attributter i en senere seksjon.

For det andre, metodene navnene på Ansatt.Bygger ikke følg JavaBean-navnekonvensjonene. Vi får se dette i neste avsnitt.

5.2. JavaBean Naming Convention

For å tvinge FreeBuilder til å følge JavaBean-navnekonvensjonen, må vi endre navn på metodene våre i Ansatt og prefiks metodene med :

@FreeBuilder offentlig grensesnitt Ansatt {String getName (); int getAge (); String getDepartment (); class Builder utvider Employee_Builder {}}

Dette vil generere getters og settere som følger JavaBean navngivningskonvensjonen:

Ansatt ansatt = byggherre .setName ("baeldung") .setAge (10) .setDepartment ("Byggmønster") .build ();

5.3. Kartleggingsmetoder

Sammen med getters og setter, legger FreeBuilder også til kartleggingsmetoder i byggeklassen. Disse kartleggingsmetodene godta en UnaryOperator som input, slik at utviklere kan beregne komplekse feltverdier.

Anta at vår Ansatt klassen har også et lønnsfelt:

@FreeBuilder offentlig grensesnitt Ansatt {Valgfritt getSalaryInUSD (); }

Anta at vi må konvertere valutaen til lønnen som er gitt som input:

lang lønnInEuros = INPUT_SALARY_EUROS; Employee.Builder builder = ny Employee.Builder (); Ansatt ansatt = byggmester .setName ("baeldung") .setAge (10) .mapSalaryInUSD (sal -> lønnInEuros * EUROS_TO_USD_RATIO) .bygg ();

FreeBuilder tilbyr slike kartleggingsmetoder for alle felt.

6. Standardverdier og begrensningskontroller

6.1. Angi standardverdier

De Ansatt.Bygger implementering vi hittil har diskutert forventer at klienten skal overføre verdier for alle felt. Faktisk mislykkes initialiseringsprosessen med en IllegalStateException i tilfelle manglende felt.

For å unngå slike feil, Vi kan enten angi standardverdier for felt eller gjøre dem valgfrie.

Vi kan sette standardverdier i Ansatt.Bygger konstruktør:

@FreeBuilder offentlig grensesnitt Ansatt {// getter metoder klasse Builder utvider Employee_Builder {public Builder () {setDepartment ("Builder Pattern"); }}}

Så vi setter ganske enkelt standardverdien avdeling i konstruktøren. Denne verdien gjelder for alle Ansatt gjenstander.

6.2. Begrensningskontroller

Vanligvis har vi visse begrensninger for feltverdier. For eksempel må en gyldig e-post inneholde en "@" eller alderen på en Ansatt må være innenfor et område.

Slike begrensninger krever at vi setter valideringer på inngangsverdiene. Og FreeBuilder lar oss legge til disse valideringene ved bare å overstyre setter metoder:

@FreeBuilder offentlig grensesnitt Ansatt {// getter metoder klasse Builder utvider Employee_Builder {@Override public Builder setEmail (String email) {if (checkValidEmail (email)) return super.setEmail (email); ellers kaste ny IllegalArgumentException ("Ugyldig e-post"); } privat boolsk checkValidEmail (streng e-post) {return email.contains ("@"); }}}

7. Valgfrie verdier

7.1. Ved hjelp av Valgfri Enger

Noen objekter inneholder valgfrie felt, hvis verdier kan være tomme eller null. FreeBuilder lar oss definere slike felt ved hjelp av Java Valgfri type:

@FreeBuilder offentlig grensesnitt Ansatt {String getName (); int getAge (); // andre getters Valgfritt getPermanent (); Valgfri getDateOfJoining (); class Builder utvider Employee_Builder {}}

Nå kan vi hoppe over å gi noen verdi for Valgfri Enger:

Ansatt ansatt = builder.setName ("baeldung") .setAge (10) .setPermanent (true) .build ();

Spesielt passerte vi ganske enkelt verdien for fast felt i stedet for et Valgfri. Siden vi ikke satt verdien for dateOfJoining felt, blir det Valgfritt. Lett () som er standard for Valgfri Enger.

7.2. Ved hjelp av @Nullable Enger

Selv om du bruker Valgfri anbefales for håndtering nulls i Java, tillater FreeBuilder oss å bruke @Nullable for bakoverkompatibilitet:

@FreeBuilder offentlig grensesnitt Ansatt {String getName (); int getAge (); // andre gettermetoder Valgfri getPermanent (); Valgfri getDateOfJoining (); @Nullable String getCurrentProject (); class Builder utvider Employee_Builder {}}

Bruken av Valgfri er dårlig anbefalt i noen tilfeller, noe som er en annen grunn til det @Nullable er foretrukket for byggherreklasser.

8. Samlinger og kart

FreeBuilder har spesiell støtte for samlinger og kart:

@FreeBuilder offentlig grensesnitt Ansatt {String getName (); int getAge (); // andre getter-metoder Liste getAccessTokens (); Kart getAssetsSerialIdMapping (); class Builder utvider Employee_Builder {}}

FreeBuilder legger til praktiske metoder for å legge til inputelementer i samlingen i byggeklassen:

Ansatt ansatt = builder.setName ("baeldung") .setAge (10) .addAccessTokens (1221819L) .addAccessTokens (1223441L, 134567L) .build ();

Det er også en getAccessTokens () metode i byggherreklassen som returnerer en umodifiserbar liste. Tilsvarende for Kart:

Ansatt ansatt = builder.setName ("baeldung") .setAge (10) .addAccessTokens (1221819L) .addAccessTokens (1223441L, 134567L) .putAssetsSerialIdMapping ("Laptop", 12345L) .build ();

De getter metode for Kart også returnerer et umodifiserbart kart til klientkoden.

9. Nestede byggherrer

For applikasjoner i den virkelige verden må vi kanskje hekker mange verdiobjekter for domenenhetene våre. Og siden de nestede objektene selv trenger byggherreimplementeringer, tillater FreeBuilder nestede byggbare typer.

Anta for eksempel at vi har en nestet kompleks type Adresse i Ansatt klasse:

@FreeBuilder offentlig grensesnitt Adresse {String getCity (); class Builder utvider Address_Builder {}}

Nå genererer FreeBuilder setter metoder som tar Adresse.Bygger som et innspill sammen med Adresse type:

Address.Builder addressBuilder = ny Address.Builder (); addressBuilder.setCity (CITY_NAME); Ansatt ansatt = builder.setName ("baeldung") .setAddress (addressBuilder) .build ();

Spesielt legger FreeBuilder også til en metode for tilpasse det eksisterende Adresse objekt i Ansatt:

Ansatt ansatt = builder.setName ("baeldung") .setAddress (addressBuilder) .mutateAddress (a -> a.setPinCode (112200)) .build ();

Sammen med FreeBuilder typer, tillater FreeBuilder også hekking av andre byggere som protos.

10. Bygge delvis gjenstand

Som vi har diskutert før, kaster FreeBuilder en IllegalStateException for eventuelle begrensninger - for eksempel manglende verdier for obligatoriske felt.

Selv om dette er ønsket for produksjonsmiljøer, det kompliserer enhetstesting som er uavhengig av begrensninger generelt.

For å slappe av slike begrensninger, tillater FreeBuilder oss å bygge delvise objekter:

Ansattes ansatt = builder.setName ("baeldung") .setAge (10) .setEmail ("[email protected]") .buildPartial (); assertNotNull (medarbeider.getEmail ());

Så selv om vi ikke har satt alle obligatoriske felt for et Ansatt, kunne vi fremdeles bekrefte at e-post feltet har en gyldig verdi.

11. Tilpasset toString () Metode

Med verdiobjekter, vi trenger ofte å legge til en egendefinert toString () gjennomføring. FreeBuilder tillater dette gjennom abstrakt klasser:

@FreeBuilder offentlig abstrakt klasse Ansatt {abstrakt String getName (); abstrakt int getAge (); @Override public String toString () {return getName () + "(" + getAge () + "år gammel)"; } offentlig statisk klasse Builder utvider Employee_Builder {}}

Vi erklærte Ansatt som en abstrakt klasse i stedet for et grensesnitt og ga en skikk toString () gjennomføring.

12. Sammenligning med andre byggebiblioteker

Byggherreimplementeringen vi har diskutert i denne artikkelen, ligner veldig på Lombok, Immutables eller andre merkeprosessorer. Derimot, det er noen kjennetegn som vi allerede har diskutert:

    • Kartleggingsmetoder
    • Nestede byggbare typer
    • Delvise gjenstander

13. Konklusjon

I denne artikkelen brukte vi FreeBuilder-biblioteket til å generere en byggeklasse i Java. Vi implementerte forskjellige tilpasninger av en byggeklasse ved hjelp av merknader, og dermed redusere kjeleplatekoden som kreves for implementeringen.

Vi så også hvordan FreeBuilder er forskjellig fra noen av de andre bibliotekene, og diskuterte kort noen av disse egenskapene i denne artikkelen.

Alle kodeeksemplene er tilgjengelige på GitHub.


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