Automatisk generering af Builder-mønsteret med FreeBuilder

1. Oversigt

I denne vejledning bruger vi FreeBuilder-biblioteket til at generere builder-klasser i Java.

2. Builder design mønster

Builder er en af ​​de mest brugte Creation Design Patterns på objektorienterede sprog. Det abstraherer instantiering af et komplekst domæneobjekt og giver en flydende API til oprettelse af en instans. Dermed hjælper det med at opretholde et kortfattet domænelag.

På trods af dets anvendelighed er en bygherre generelt kompleks at implementere, især i Java. Selv enklere værdiobjekter kræver en masse kedelpladekode.

3. Builder Implementering i Java

Før vi fortsætter med FreeBuilder, lad os implementere en kedelpladebygger til vores Medarbejder klasse:

offentlig klassemedarbejder {privat endelig strengnavn; privat afsluttende alder privat endelig String afdeling; privat medarbejder (strengnavn, alder, strengafdeling) {this.name = navn; this.age = alder; dette. afdeling = afdeling; }}

Og en indre Bygger klasse:

offentlig statisk klasse Builder {privat strengnavn; privat int alder privat streng afdeling; public Builder setName (strengnavn) {this.name = navn; returner dette; } public Builder setAge (int age) {this.age = age; returner dette; } public Builder setDepartment (strengafdeling) {this.department = afdeling; returner dette; } offentlig ansat build () {returner ny medarbejder (navn, alder, afdeling); }}

Derfor kan vi nu bruge bygherren til at instantere Medarbejder objekt:

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

Som vist ovenfor, en masse kedelpladekode er nødvendig for at implementere en builder-klasse.

I de senere afsnit vil vi se, hvordan FreeBuilder med det samme kan forenkle denne implementering.

4. Maven afhængighed

For at tilføje FreeBuilder-biblioteket tilføjer vi FreeBuilder Maven-afhængighed i vores pom.xml:

 org.inferred freebuilder 2.4.1 

5. FreeBuilder Kommentar

5.1. Generering af en Builder

FreeBuilder er et open source-bibliotek, der hjælper udviklere med at undgå kogepladekoden, mens de implementerer builderklasser. Det gør brug af annoteringsbehandling i Java til at generere en konkret implementering af bygningsmønsteret.

Godt kommentere vores Medarbejder klasse fra det tidligere afsnit med @FreeBuilderog se hvordan det automatisk genererer bygherreklassen:

@FreeBuilder offentlig grænseflade Medarbejder {Strengnavn (); int alder (); Strengafdeling (); class Builder udvider Employee_Builder {}}

Det er vigtigt at påpege det Medarbejder er nu en interfacesnarere end en POJO-klasse. Desuden indeholder den alle attributterne til en Medarbejder objekt som metoder.

Før vi fortsætter med at bruge denne builder, skal vi konfigurere vores IDE'er for at undgå kompileringsproblemer. Siden FreeBuilder genererer automatisk Medarbejder_Bygger klasse under kompilering, IDE klager normalt over ClassNotFoundException på linje nummer 8.

For at undgå sådanne problemer, Vi har brug for at muliggøre annoteringsbehandling i IntelliJ eller Eclipse. Og mens vi gør det, bruger vi FreeBuilder's annoteringsprocessor org.inferred.freebuilder.processor.Processor. Derudover skal den mappe, der bruges til at generere disse kildefiler, være markeret som Generated Sources Root.

Alternativt vi kan også udføre mvn installere at opbygge projektet og generere de krævede byggeklasser.

Endelig har vi samlet vores projekt og kan nu bruge Medarbejder.Bygger klasse:

Employee.Builder builder = ny Employee.Builder (); Medarbejdermedarbejder = builder.name ("baeldung") .age (10). Afdeling ("Builder Pattern") .build ();

Alt i alt er der to hovedforskelle mellem dette og den byggeklasse, vi så tidligere. Først, vi skal indstille værdien for alle attributter til Medarbejder klasse. Ellers kaster det en IllegalStateException.

Vi får se, hvordan FreeBuilder håndterer valgfrie attributter i et senere afsnit.

For det andet er metodens navne på Medarbejder.Bygger følg ikke JavaBean-navngivningskonventionerne. Vi ser dette i næste afsnit.

5.2. JavaBean Naming Convention

For at tvinge FreeBuilder til at følge JavaBean-navngivningskonventionen, skal vi omdøbe vores metoder i Medarbejder og præfiks metoderne med :

@FreeBuilder offentlig grænseflade Medarbejder {String getName (); int getAge (); String getDepartment (); class Builder udvider Employee_Builder {}}

Dette vil generere getters og settere, der følger JavaBean navngivningskonventionen:

Medarbejdermedarbejder = builder .setName ("baeldung") .setAge (10) .setDepartment ("Builder Pattern") .build ();

5.3. Kortlægningsmetoder

Sammen med getters og setters tilføjer FreeBuilder også kortlægningsmetoder i builder-klassen. Disse kortlægningsmetoder accepter en UnaryOperator som input, derved tillader udviklere at beregne komplekse feltværdier.

Antag vores Medarbejder klasse har også et lønfelt:

@FreeBuilder offentlig grænseflade Medarbejder {Valgfri getSalaryInUSD (); }

Antag nu, at vi har brug for at konvertere valutaen for den løn, der leveres som input:

lang lønInEuros = INPUT_SALARY_EUROS; Employee.Builder builder = ny Employee.Builder (); Medarbejdermedarbejder = bygherre .setName ("baeldung") .setAge (10) .mapSalaryInUSD (sal -> lønInEuros * EUROS_TO_USD_RATIO) .build ();

FreeBuilder leverer sådanne kortlægningsmetoder til alle felter.

6. Standardværdier og begrænsningskontrol

6.1. Indstilling af standardværdier

Det Medarbejder.Bygger implementering, vi hidtil har diskuteret, forventer, at klienten overfører værdier til alle felter. Faktisk mislykkes initialiseringsprocessen med en IllegalStateException i tilfælde af manglende felter.

For at undgå sådanne fejl, Vi kan enten indstille standardværdier for felter eller gøre dem valgfri.

Vi kan indstille standardværdier i Medarbejder.Bygger konstruktør:

@FreeBuilder offentlig grænseflade Medarbejder {// getter metoder klasse Builder udvider Employee_Builder {public Builder () {setDepartment ("Builder Pattern"); }}}

Så vi indstiller simpelthen standardværdien afdeling i konstruktøren. Denne værdi gælder for alle Medarbejder genstande.

6.2. Begrænsningskontrol

Normalt har vi visse begrænsninger for feltværdier. For eksempel skal en gyldig e-mail indeholde et “@” eller alderen på en Medarbejder skal være inden for et interval.

Sådanne begrænsninger kræver, at vi lægger valideringer på inputværdier. Og FreeBuilder giver os mulighed for at tilføje disse valideringer ved blot at tilsidesætte setter metoder:

@FreeBuilder offentlig grænseflade Medarbejder {// getter metoder klasse Builder udvider Employee_Builder {@Override public Builder setEmail (String email) {if (checkValidEmail (email)) return super.setEmail (email); ellers smid nyt IllegalArgumentException ("Ugyldig e-mail"); } privat boolsk checkValidEmail (streng e-mail) {return email.contains ("@"); }}}

7. Valgfri værdier

7.1. Ved brug af Valgfri Felter

Nogle objekter indeholder valgfri felter, hvis værdier kan være tomme eller nul. FreeBuilder giver os mulighed for at definere sådanne felter ved hjælp af Java Valgfri type:

@FreeBuilder offentlig grænseflade Medarbejder {String getName (); int getAge (); // andre getters Valgfri getPermanent (); Valgfri getDateOfJoining (); class Builder udvider Employee_Builder {}}

Nu springer vi muligvis over at give nogen værdi for Valgfri felter:

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

Især passerede vi simpelthen værdien for permanent felt i stedet for et Valgfri. Da vi ikke satte os værdien for dateOfJoining felt, bliver det Valgfri. Let () som er standard for Valgfri felter.

7.2. Ved brug af @Nullable Felter

Selvom du bruger Valgfri anbefales til håndtering nuls i Java tillader FreeBuilder os at bruge @Nullable for bagudkompatibilitet:

@FreeBuilder offentlig grænseflade Medarbejder {String getName (); int getAge (); // andre getter-metoder Valgfri getPermanent (); Valgfri getDateOfJoining (); @Nullable String getCurrentProject (); class Builder udvider Employee_Builder {}}

Brugen af Valgfri er dårligt anbefalet i nogle tilfælde, hvilket er en anden grund til @Nullable foretrækkes til byggeklasser.

8. Samlinger og kort

FreeBuilder har særlig support til samlinger og kort:

@FreeBuilder offentlig grænseflade Medarbejder {String getName (); int getAge (); // andre getter-metoder Liste getAccessTokens (); Kort getAssetsSerialIdMapping (); class Builder udvider Employee_Builder {}}

FreeBuilder tilføjer bekvemmelighed metoder til at tilføje inputelementer til samlingen i builder klasse:

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

Der er også en getAccessTokens () metode i byggeklassen, hvilken returnerer en umodificerbar liste. Tilsvarende for Kort:

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

Det getter metode til Kort også returnerer et umodificerbart kort til klientkoden.

9. Indlejrede bygherrer

For applikationer i den virkelige verden må vi muligvis nest en masse værdigenstande til vores domæneenheder. Og da de indlejrede objekter i sig selv kan have brug for builderimplementeringer, tillader FreeBuilder indlejrede typer, der kan bygges.

Antag for eksempel, at vi har en indlejret kompleks type Adresse i Medarbejder klasse:

@FreeBuilder offentlig grænseflade Adresse {String getCity (); class Builder udvider Address_Builder {}}

Nu genererer FreeBuilder setter metoder, der tager Adresse.Bygger som input sammen med Adresse type:

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

Især tilføjer FreeBuilder også en metode til tilpasse det eksisterende Adresse objekt i Medarbejder:

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

Sammen med FreeBuilder typer tillader FreeBuilder også indlejring af andre bygherrer som f.eks. protos.

10. Bygning af delvis objekt

Som vi har diskuteret før, kaster FreeBuilder en IllegalStateException for enhver overtrædelse af begrænsninger - for eksempel manglende værdier for obligatoriske felter.

Selvom dette er ønsket til produktionsmiljøer, det komplicerer enhedstest, der er uafhængig af begrænsninger generelt.

For at slappe af sådanne begrænsninger tillader FreeBuilder os at oprette delvise objekter:

Medarbejdermedarbejder = builder.setName ("baeldung") .setAge (10) .setEmail ("[email protected]") .buildPartial (); assertNotNull (medarbejder.getEmail ());

Så selvom vi ikke har indstillet alle obligatoriske felter til en Medarbejder, kunne vi stadig kontrollere, at e-mail felt har en gyldig værdi.

11. Brugerdefineret toString () Metode

Med værdiobjekter, vi har ofte brug for at tilføje en brugerdefineret toString () implementering. FreeBuilder tillader dette igennem abstrakt klasser:

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

Vi erklærede Medarbejder som en abstrakt klasse snarere end en grænseflade og leverede en brugerdefineret toString () implementering.

12. Sammenligning med andre bygningsbiblioteker

Builderimplementeringen, vi har diskuteret i denne artikel, ligner meget dem fra Lombok, Immutables eller enhver anden annoteringsprocessor. Imidlertid, der er et par kendetegn som vi allerede har diskuteret:

    • Kortlægningsmetoder
    • Indlejrede typer, der kan bygges
    • Delvise genstande

13. Konklusion

I denne artikel brugte vi FreeBuilder-biblioteket til at generere en builder-klasse i Java. Vi implementerede forskellige tilpasninger af en builder-klasse ved hjælp af annoteringer, og dermed reducere den kedelpladekode, der kræves til implementeringen.

Vi så også, hvordan FreeBuilder adskiller sig fra nogle af de andre biblioteker, og diskuterede kort nogle af disse egenskaber i denne artikel.

Alle kodeeksemplerne er tilgængelige på GitHub.


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