Automatsko generiranje graditeljskog uzorka s FreeBuilder-om

1. Pregled

U ovom uputstvu koristit ćemo knjižnicu FreeBuilder za generiranje graditeljskih klasa u Javi.

2. Uzorak dizajnera graditelja

Builder je jedan od najčešće korištenih uzoraka dizajna kreacije u objektno orijentiranim jezicima. To apstrahira instanciju složenog objekta domene i pruža tečni API za stvaranje instance. Time pomaže u održavanju sažetog sloja domene.

Unatoč svojoj korisnosti, graditelj je općenito složen za implementaciju, posebno u Javi. Čak i jednostavniji objekti vrijednosti zahtijevaju puno uzorka.

3. Implementacija graditelja u Javi

Prije nego što nastavimo s FreeBuilder-om, hajde da implementiramo graditelj ploča za naš Zaposlenik razred:

zaposlenik u javnoj klasi {private final String name; privatni konačni int age; privatni završni gudački odjel; privatni zaposlenik (ime niza, int age, odjel niza) {this.name = name; this.age = dob; this.department = odjel; }}

I unutarnji Graditelj razred:

javni statički graditelj klasa {naziv privatnog niza; privatno int doba; privatni gudački odjel; javni graditelj setName (ime niza) {this.name = name; vrati ovo; } javni graditelj setAge (int age) {this.age = age; vrati ovo; } javni graditelj setDepartment (odjel niza) {this.department = odjel; vrati ovo; } public Employee build () {return new Employee (ime, dob, odjel); }}

U skladu s tim, sada graditelj možemo koristiti za instanciranje Zaposlenik objekt:

Employee.Builder emplBuilder = novi Employee.Builder (); Zaposlenik zaposlenik = emplBuilder .setName ("baeldung") .setAge (12) .setDepartment ("Uzorak graditelja") .build ();

Kao što je prikazano gore, za implementaciju klase graditelja potrebno je puno šifre uzorka.

U kasnijim odjeljcima vidjet ćemo kako FreeBuilder može trenutno pojednostaviti ovu implementaciju.

4. Ovisnost Mavena

Da bismo dodali knjižnicu FreeBuilder, u našu ćemo dodati ovisnost FreeBuilder Maven pom.xml:

 org. pretpostavljeni slobodni graditelj 2.4.1 

5. FreeBuilder Bilješka

5.1. Generiranje graditelja

FreeBuilder je biblioteka otvorenog koda koja pomaže programerima da izbjegnu šifru uzorka tijekom implementacije klasa graditelja. Koristi obradu bilješki u Javi za generiranje konkretne provedbe uzora graditelja.

Dobro bilježiti naše Zaposlenik razred iz ranijeg odjeljka sa @FreeBuilderi pogledajte kako automatski generira graditeljsku klasu:

@FreeBuilder javno sučelje Zaposlenik {Ime niza (); int dob ​​(); Gudački odjel (); class Builder proširuje Employee_Builder {}}

Važno je to istaknuti Zaposlenik je sada sučeljenego POJO klasa. Nadalje, sadrži sve atribute Zaposlenik objekt kao metode.

Prije nego što nastavimo koristiti ovaj graditelj, moramo konfigurirati IDE-ove kako bismo izbjegli probleme s kompilacijom. Od FreeBuilder automatski generira Employee_Builder klasa tijekom kompilacije, IDE obično se žali na ClassNotFoundException na liniji broj 8.

Da biste izbjegli takve probleme, moramo omogućiti obradu napomena u IntelliJ-u ili Eclipseu. I pritom ćemo koristiti FreeBuilder-ov procesor za napomene org.inferred.freebuilder.processor.Processor. Uz to, direktorij koji se koristi za generiranje tih izvornih datoteka trebao bi biti označen kao generirani korijen izvora.

Alternativno, možemo i izvršiti mvn instalirati za izgradnju projekta i generiranje potrebnih klasa graditelja.

Napokon, sastavili smo naš projekt i sada možemo koristiti Zaposlenik.Builder razred:

Builder Employee.Builder = novi Employee.Builder (); Zaposlenik zaposlenik = graditelj.ime ("baeldung") .age (10) .department ("Uzorak graditelja") .build ();

Sve u svemu, dvije su glavne razlike između ove i klase graditelja koje smo ranije vidjeli. Prvi, moramo postaviti vrijednost za sve atribute Zaposlenik razred. Inače, baca znak IllegalStateException.

Kako će FreeBuilder rukovati neobaveznim atributima, vidjet ćemo u kasnijem odjeljku.

Drugo, imena metoda Zaposlenik.Builder nemojte slijediti JavaBean konvencije imenovanja. To ćemo vidjeti u sljedećem odjeljku.

5.2. Konvencija o imenovanju JavaBean

Da bismo prisilili FreeBuilder da slijedi JavaBean konvenciju imenovanja, moramo preimenovati naše metode u Zaposlenik i prefiksirajte metode sa dobiti:

@FreeBuilder javno sučelje Employee {String getName (); int getAge (); String getDepartment (); class Builder proširuje Employee_Builder {}}

Ovo će generirati gettere i postavljače koji slijede JavaBean konvenciju imenovanja:

Zaposlenik zaposlenik = graditelj .setName ("baeldung") .setAge (10) .setDepartment ("Uzorak graditelja") .build ();

5.3. Metode mapiranja

Zajedno s getterima i setterima, FreeBuilder također dodaje metode mapiranja u klasi graditelja. Ove metode mapiranja prihvatite UnaryOperator kao ulaz, čime se programerima omogućuje izračunavanje složenih vrijednosti polja.

Pretpostavimo naš Zaposlenik razred također ima polje za plaću:

@FreeBuilder javno sučelje Zaposlenik {Neobvezno getSalaryInUSD (); }

Sada pretpostavimo da moramo pretvoriti valutu plaće koja je navedena kao ulaz:

duga plaćaInEuros = INPUT_SALARY_EUROS; Builder Employee.Builder = novi Employee.Builder (); Zaposlenik zaposlenik = graditelj .setName ("baeldung") .setAge (10) .mapSalaryInUSD (sal -> plataInEuros * EUROS_TO_USD_RATIO) .build ();

FreeBuilder nudi takve metode mapiranja za sva polja.

6. Zadane vrijednosti i provjere ograničenja

6.1. Postavljanje zadanih vrijednosti

The Zaposlenik.Builder implementacija o kojoj smo do sada razgovarali očekuje da klijent proslijedi vrijednosti za sva polja. Zapravo, on ne uspijeva započeti postupak inicijalizacije s IllegalStateException u slučaju nedostajanja polja.

Da bi se izbjegli takvi kvarovi, možemo postaviti zadane vrijednosti za polja ili ih učiniti neobaveznim.

Možemo postaviti zadane vrijednosti u Zaposlenik.Builder konstruktor:

@FreeBuilder javno sučelje Employee {// getter methods class Builder proširuje Employee_Builder {public Builder () {setDepartment ("Uzorak graditelja"); }}}

Tako smo jednostavno postavili zadani odjel u konstruktoru. Ova se vrijednost odnosi na sve Zaposlenik predmeta.

6.2. Provjere ograničenja

Obično imamo određena ograničenja vrijednosti polja. Na primjer, valjana e-adresa mora sadržavati "@" ili dob od Zaposlenik mora biti unutar dometa.

Takva ograničenja zahtijevaju da stavimo validacije na ulazne vrijednosti. I FreeBuilder nam omogućuje dodavanje ovih provjera jednostavnim nadjačavanjem seter metode:

@FreeBuilder javno sučelje Employee {// getter methods class Builder proširuje Employee_Builder {@Override public Builder setEmail (String email) {if (checkValidEmail (email)) return super.setEmail (email); inače baci novi IllegalArgumentException ("Nevaljana e-adresa"); } private boolean checkValidEmail (string e-pošte) {return email.contains ("@"); }}}

7. Izborne vrijednosti

7.1. Koristeći Neobvezno Polja

Neki objekti sadrže neobavezna polja, vrijednosti za koje mogu biti prazne ili nule. FreeBuilder nam omogućuje definiranje takvih polja pomoću Jave Neobvezno tip:

@FreeBuilder javno sučelje Employee {String getName (); int getAge (); // ostali geteri Neobvezno getPermanent (); Neobvezno getDateOfJoining (); class Builder proširuje Employee_Builder {}}

Sada možemo preskočiti davanje bilo koje vrijednosti za Neobvezno polja:

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

Značajno je da smo jednostavno prenijeli vrijednost za trajni polje umjesto Neobvezno. Pošto nismo postavili vrijednost za dateOfJoining polje, bit će Neobvezno.prazno () koji je zadani za Neobvezno polja.

7.2. Koristeći @Nullable Polja

Iako se koristi Neobvezno preporučuje se za rukovanje nulls u Javi, FreeBuilder omogućuje nas koristiti @Nullable za povratnu kompatibilnost:

@FreeBuilder javno sučelje Employee {String getName (); int getAge (); // ostale metode dobivanja Neobvezno getPermanent (); Neobvezno getDateOfJoining (); @Nullable String getCurrentProject (); class Builder proširuje Employee_Builder {}}

Korištenje Neobvezno je u nekim slučajevima loše savjetovan što je još jedan razlog zašto @Nullable poželjno je za klase graditelja.

8. Zbirke i karte

FreeBuilder ima posebnu podršku za zbirke i mape:

@FreeBuilder javno sučelje Employee {String getName (); int getAge (); // ostale metode dobivanja Popis getAccessTokens (); Karta getAssetsSerialIdMapping (); class Builder proširuje Employee_Builder {}}

FreeBuilder dodaje praktične metode za dodavanje ulaznih elemenata u Zbirku u klasi graditelja:

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

Tu je i getAccessTokens () metoda u klasi graditelja koja vraća nepromjenjiv popis. Slično tome, za Karta:

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

The getter metoda za Karta također vraća nepromjenjivu mapu kodu klijenta.

9. Ugniježđeni graditelji

Za stvarne aplikacije možda ćemo morati ugnijezdi puno vrijednosnih objekata za entitete naše domene. A budući da ugniježđeni objekti i sami mogu trebati implementacije graditelja, FreeBuilder dopušta ugniježđene vrste građenja.

Na primjer, pretpostavimo da imamo ugniježđeni složeni tip Adresa u Zaposlenik razred:

Adresa javnog sučelja @FreeBuilder {String getCity (); class Builder proširuje Address_Builder {}}

Sada FreeBuilder generira seter metode koje uzimaju Adresa.Builder kao ulaz zajedno sa Adresa tip:

Address.Builder addressBuilder = novi Address.Builder (); addressBuilder.setCity (CITY_NAME); Zaposlenik zaposlenik = builder.setName ("baeldung") .setAddress (addressBuilder) .build ();

Značajno je da FreeBuilder također dodaje metodu prilagoditi postojeće Adresa objekt u Zaposlenik:

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

Zajedno s FreeBuilder tipova, FreeBuilder također omogućuje gniježđenje drugih graditelja, poput protosa.

10. Izgradnja djelomičnog objekta

Kao što smo već razgovarali, FreeBuilder baca datoteku IllegalStateException za svako kršenje ograničenja - na primjer, vrijednosti koje nedostaju za obavezna polja.

Iako je ovo poželjno za proizvodna okruženja, komplicira jedinično ispitivanje koje je neovisno o ograničenjima općenito.

Da bi ublažio takva ograničenja, FreeBuilder nam omogućuje izradu djelomičnih objekata:

Zaposlenik zaposlenik = builder.setName ("baeldung") .setAge (10) .setEmail ("[email protected]") .buildPartial (); assertNotNull (worker.getEmail ());

Dakle, iako nismo postavili sva obavezna polja za Zaposlenik, još uvijek bismo mogli provjeriti je li e-mail polje ima valjanu vrijednost.

11. Prilagođeno toString () Metoda

S objektima vrijednosti, često moramo dodati običaj toString () provedba. FreeBuilder to omogućuje sažetak klase:

@FreeBuilder javni sažetak klase Employee {abstract String getName (); sažetak int getAge (); @Override public String toString () {return getName () + "(" + getAge () + "old old)"; } javni graditelj statičkih klasa proširuje Employee_Builder {}}

Izjavili smo Zaposlenik kao apstraktna klasa, a ne kao sučelje i pružao je običaj toString () provedba.

12. Usporedba s ostalim knjižnicama graditelja

Implementacija graditelja o kojoj smo raspravljali u ovom članku vrlo je slična onima iz Lomboka, Immutables-a ili bilo kojeg drugog procesora bilješki. Međutim, postoji nekoliko karakterističnih obilježja o kojem smo već razgovarali:

    • Metode mapiranja
    • Ugniježđene ugradive vrste
    • Djelomični objekti

13. Zaključak

U ovom smo članku koristili knjižnicu FreeBuilder za generiranje graditeljske klase u Javi. Proveli smo razne prilagodbe klase graditelja uz pomoć bilješki, čime se smanjuje šifra tipa koja je potrebna za njegovu provedbu.

Također smo vidjeli kako se FreeBuilder razlikuje od nekih drugih knjižnica i ukratko smo raspravili neke od tih karakteristika u ovom članku.

Svi primjeri koda dostupni su na GitHubu.