Java konstruktori vs statičke tvorničke metode

1. Pregled

Java konstruktori zadani su mehanizam za dobivanje potpuno inicijaliziranih instanci klase. Napokon, oni pružaju svu infrastrukturu potrebnu za ubrizgavanje ovisnosti, bilo ručno ili automatski.

Unatoč tome, u nekoliko specifičnih slučajeva korištenja, poželjno je pribjeći statičkim tvorničkim metodama za postizanje istog rezultata.

U ovom uputstvu istaknut ćemo prednosti i nedostaci upotrebe statičkih tvorničkih metoda u odnosu na obične stare Java konstruktore.

2. Prednosti statičkih tvorničkih metoda nad konstruktorima

U objektno orijentiranom jeziku poput Jave, što može biti pogrešno s konstruktorima? Sve u svemu, ništa. Unatoč tome, učinkovita Java stavka 1 slavnog Joshua Blocka jasno kaže:

"Razmotrite statičke tvorničke metode umjesto konstruktora"

Iako ovo nije srebrni metak, evo najvažnijih razloga koji podržavaju ovaj pristup:

  1. Konstruktori nemaju suvisla imena, tako da su uvijek ograničeni na standardnu ​​konvenciju imenovanja koju nameće jezik. Statičke tvorničke metode mogu imati suvisla imena, dakle izričito prenoseći ono što rade
  2. Statičke tvorničke metode mogu vratiti isti tip koji implementira metodu (e), podtip i također primitivi, tako da nude fleksibilniji raspon vrsta povratnika
  3. Statičke tvorničke metode mogu inkapsulirati svu logiku potrebnu za predkonstrukciju potpuno inicijaliziranih instanci, tako da se mogu koristiti za premještanje ove dodatne logike iz konstruktora. To sprečava konstruktore u izvođenju daljnjih zadataka, osim puke inicijalizacije polja
  4. Statičke tvorničke metode mogu se kontrolirati pomoću primjera, pri čemu je Singleton uzorak najočitiji primjer ove značajke

3. Statičke tvorničke metode u JDK

U JDK postoji mnoštvo primjera statičkih tvorničkih metoda koje pokazuju mnoge gore navedene prednosti. Istražimo neke od njih.

3.1. The Niz Razred

Zbog dobro poznatog Niz interniranje, vrlo je malo vjerojatno da ćemo koristiti Niz konstruktor klase za stvaranje novog Niz objekt. Bez obzira na to, ovo je potpuno legalno:

Vrijednost niza = novi niz ("Baeldung");

U ovom slučaju, konstruktor će stvoriti novi Niz objekt, što je očekivano ponašanje.

Alternativno, ako želimo stvoriti novi Niz objekt pomoću statičke tvorničke metode, možemo koristiti neke od sljedećih implementacija vrijednost() metoda:

Vrijednost niza1 = String.valueOf (1); Vrijednost niza2 = String.valueOf (1,0L); Vrijednost niza3 = String.valueOf (true); Vrijednost niza4 = String.valueOf ('a'); 

Postoji nekoliko preopterećenih implementacija vrijednost(). Svaka će vratiti novu Niz objekt, ovisno o vrsti argumenta prosljeđenog metodi (npr. int, dugo, boolean, char, i tako dalje).

Ime prilično jasno izražava ono što metoda radi. Također se drži dobro uspostavljenog standarda u ekosustavu Java za imenovanje statičkih tvorničkih metoda.

3.2. The Neobvezno Razred

Još jedan lijep primjer statičkih tvorničkih metoda u JDK je Neobvezno razred. Ovaj sat implementira nekoliko tvorničkih metoda s prilično suvislim imenima, uključujući prazan(), od(), i odNullable ():

Neobvezna vrijednost1 = Neobvezna.empty (); Izborna vrijednost2 = Izborna.of ("Baeldung"); Izborna vrijednost3 = Izborna.ofNullable (null);

3.3. The Zbirke Razred

Sasvim moguće najreprezentativniji primjer statičkih tvorničkih metoda u JDK je Zbirke razred. Ovo je klasa koja se ne može instalirati i koja implementira samo statičke metode.

Mnoge od njih su tvorničke metode koje također vraćaju zbirke nakon primjene neke vrste algoritma na isporučenu zbirku.

Evo nekoliko tipičnih primjera tvorničkih metoda klase:

Zbirka syncedCollection = Collections.synchronizedCollection (originalCollection); Postavi syncedSet = Collections.synchronizedSet (novi HashSet ()); Popis unmodifiableList = Collections.unmodifiableList (originalList); Karta unmodifiableMap = Collections.unmodifiableMap (originalMap); 

Broj statičkih tvorničkih metoda u JDK stvarno je opsežan, pa ćemo popis kratkoći radi kratkosti.

Ipak, gornji primjeri trebali bi nam dati jasnu predodžbu o tome kako su sveprisutne statičke tvorničke metode u Javi.

4. Prilagođene statičke tvorničke metode

Naravno, možemo implementirati vlastite statičke tvorničke metode. Ali kada to zaista vrijedi učiniti, umjesto da stvaramo instance klase pomoću običnih konstruktora?

Pogledajmo jednostavan primjer.

Razmotrimo ovo naivno Korisnik razred:

korisnik javne klase {privatni konačni naziv niza; privatna završna adresa e-pošte; privatna završna Zemlja gudača; javni korisnik (ime niza, niz e-pošte, država niza) {this.name = name; this.email = email; this.country = zemlja; } // standardni getteri / toString}

U ovom slučaju, nema vidljivih upozorenja koja ukazuju na to da bi statička tvornička metoda mogla biti bolja od standardnog konstruktora.

Što ako to želimo sve Korisnik instance dobivaju zadanu vrijednost za zemlja polje?

Ako polje inicijaliziramo zadanom vrijednošću, morali bismo i refaktorirati konstruktor, čineći tako dizajn rigidnijim.

Umjesto toga možemo koristiti statičku tvorničku metodu:

javni statični korisnik createWithDefaultCountry (naziv niza, niz e-pošte) {vrati novog korisnika (ime, e-adresa, "Argentina"); }

Evo kako bismo dobili Korisnik instance sa zadanom vrijednošću dodijeljenom zemlja polje:

Korisnik korisnik = User.createWithDefaultCountry ("John", "[e-pošta zaštićena]");

5. Premještanje logike iz konstruktora

Naše Korisnik klasa bi mogla brzo propasti u pogrešnom dizajnu ako odlučimo implementirati značajke koje bi zahtijevale dodavanje dodatne logike u konstruktor (zvona alarma trebala bi se oglasiti do tog trenutka).

Pretpostavimo da želimo razredu pružiti mogućnost bilježenja vremena u kojem svaki Korisnik objekt je stvoren.

Ako samo stavimo ovu logiku u konstruktor, prekršili bismo princip jedinstvene odgovornosti. Na kraju bismo dobili monolitni konstruktor koji čini puno više od inicijalizacije polja.

Svoj dizajn možemo održavati čistim statičkom tvorničkom metodom:

javna klasa Korisnik {private static final Logger LOGGER = Logger.getLogger (User.class.getName ()); privatni konačni naziv niza; privatna završna adresa e-pošte; privatna završna Zemlja gudača; // standardni konstruktori / getteri javni statički korisnik createWithLoggedInstantiationTime (naziv niza, niz e-pošte, država niza) {LOGGER.log (Level.INFO, "Izrada korisničke instance na: {0}", LocalTime.now ()); vratiti novog korisnika (ime, e-adresa, država); }} 

Evo kako bismo kreirali naš poboljšani Korisnik primjer:

Korisnik korisnik = User.createWithLoggedInstantiationTime ("John", "[email protected]", "Argentina");

6. Instanciranje pod nadzorom instance

Kao što je gore prikazano, možemo integrirati dijelove logike u statičke tvorničke metode prije nego što se vratimo potpuno inicijalizirani Korisnik predmeta. To možemo učiniti bez da zagađujemo konstruktor odgovornim za izvođenje višestrukih, nepovezanih zadataka.

Na primjer, pretpostavimo da želimo napraviti svoje Korisnik razred a Singleton. To možemo postići primjenom statičke tvorničke metode kontrolirane instancom:

javna klasa Korisnik {private static volatile User instance = null; // ostala polja / standardni konstruktori / getteri javni statički korisnik getSingletonInstance (naziv niza, niz e-pošte, država niza) {if (instance == null) {sinkronizirano (User.class) {if (instance == null) {instance = new Korisnik (ime, e-adresa, država); }}} return instanca; }} 

Provedba getSingletonInstance () metoda je sigurno na nit, s malom kaznom izvedbe, zbog sinkroniziranog bloka.

U ovom smo slučaju koristili lijenu inicijalizaciju kako bismo demonstrirali provedbu instance tvornički kontrolirane statičke metode.

Vrijedno je, međutim, spomenuti to najbolji način za implementaciju Singletona je s Javom nabrajanje tipa, jer je istovremeno siguran i za serializaciju i za nit. Potpune detalje o tome kako implementirati Singletone koristeći različite pristupe potražite u ovom članku.

Očekivano, dobivanje a Korisnik objekt s ovom metodom izgleda vrlo slično prethodnim primjerima:

Korisnik korisnik = User.getSingletonInstance ("John", "[e-pošta zaštićena]", "Argentina");

7. Zaključak

U ovom smo članku istražili nekoliko slučajeva korištenja gdje statičke tvorničke metode mogu biti bolja alternativa korištenju običnih Java konstruktora.

Štoviše, ovaj obrazac refaktoriranja toliko je čvrsto ukorijenjen u tipičan tijek rada da će ga većina IDE-a učiniti umjesto nas.

Naravno, Apache NetBeans, IntelliJ IDEA i Eclipse izvršit će refaktoriranje na malo drugačije načine, pa vas molimo da prvo provjerite svoju IDE dokumentaciju.

Kao i kod mnogih drugih obrazaca refaktoriranja, i mi bismo trebali koristiti statičke tvorničke metode s dužnim oprezom, i to samo onda kada se isplati razmjenjivati ​​se između izrade fleksibilnijih i čistijih dizajna i troškova primjene dodatnih metoda.

Kao i obično, svi uzorci koda prikazani u ovom članku dostupni su na GitHubu.