Java Constructors vs Static Factory Methods

1. Prehľad

Konštruktory Java sú predvoleným mechanizmom na získanie plne inicializovaných inštancií tried. Koniec koncov, poskytujú všetku infraštruktúru potrebnú na vkladanie závislostí, či už manuálne alebo automaticky.

Aj napriek tomu je v niekoľkých konkrétnych prípadoch použitia na dosiahnutie rovnakého výsledku vhodnejšie použiť statické továrenské metódy.

V tomto návode zdôrazníme klady a zápory používania metód statickej továrne vs obyčajné staré konštruktory Java.

2. Výhody statických výrobných metód oproti konštruktérom

Čo môže byť v objektovo orientovanom jazyku, ako je Java, s konštruktérmi zlé? Celkovo nič. Aj napriek tomu je v položke Effective Java Item 1 známeho Joshua Block jasne uvedené:

"Zvážte statické továrenské metódy namiesto konštruktorov"

Aj keď nejde o striebornú guľku, tu sú najpodstatnejšie dôvody, ktoré tento prístup podporujú:

  1. Konštruktéri nemajú zmysluplné názvy, takže sa vždy obmedzujú na štandardné pomenovacie konvencie stanovené jazykom. Statické továrenské metódy môžu mať zmysluplné názvy, a teda výslovne vyjadrujú, čo robia
  2. Statické továrenské metódy môžu vracať rovnaký typ, ktorý implementuje metódu (metódy), podtyp a tiež primitívy, takže ponúkajú flexibilnejšiu škálu návratných typov
  3. Statické továrenské metódy môžu zapuzdriť všetku logiku potrebnú na predbežnú konštrukciu plne inicializovaných inštancií, takže ich možno použiť na presunutie tejto ďalšej logiky z konštruktorov. Toto bráni konštruktérom v plnení ďalších úloh, iných ako je len inicializácia polí
  4. Statické továrenské metódy je možné riadiť pomocou inštančných metód, pričom vzor Singleton je najvýraznejším príkladom tejto funkcie

3. Statické továrenské metódy v JDK

V JDK existuje veľa príkladov statických továrenských metód, ktoré ukazujú veľa z výhod uvedených vyššie. Poďme preskúmať niektoré z nich.

3.1. The String Trieda

Kvôli známemu String interning, je veľmi nepravdepodobné, že použijeme String konštruktor triedy na vytvorenie nového String objekt. Napriek tomu je to úplne legálne:

Hodnota reťazca = nový reťazec ("Baeldung");

V takom prípade konštruktor vytvorí nový String objekt, čo je očakávané správanie.

Prípadne, ak chceme vytvoriť nový String objekt pomocou statickej továrenskej metódy, môžeme použiť niektoré z nasledujúcich implementácií hodnota() metóda:

Reťazcová hodnota1 = String.valueOf (1); Reťazcová hodnota2 = String.valueOf (1.0L); Reťazcová hodnota3 = String.valueOf (true); Reťazcová hodnota4 = String.valueOf ('a'); 

Existuje niekoľko preťažených implementácií hodnota(). Každý z nich vráti nový String objekt, v závislosti od typu argumentu odovzdaného metóde (napr. int, dlho, boolovský, char, a tak ďalej).

Názov vyjadruje celkom jasne, čo metóda robí. Drží sa tiež osvedčeného štandardu v ekosystéme Java pre pomenovanie statických továrenských metód.

3.2. The Voliteľné Trieda

Ďalším elegantným príkladom statických továrenských metód v JDK je Voliteľné trieda. Táto trieda implementuje niekoľko továrenských metód s dosť zmysluplnými názvami, počítajúc do toho prázdne (), z ()a ofNullable ():

Voliteľná hodnota1 = Optional.empty (); Voliteľná hodnota2 = Optional.of ("Baeldung"); Voliteľná hodnota3 = Voliteľná.ofNullable (null);

3.3. The Zbierky Trieda

Dosť možno najreprezentatívnejším príkladom statických továrenských metód v JDK je Zbierky trieda. Toto nie je inštančná trieda, ktorá implementuje iba statické metódy.

Mnohé z nich sú továrenské metódy, ktoré vracajú kolekcie aj po použití určitého typu algoritmu na dodanú kolekciu.

Tu je niekoľko typických príkladov továrenských metód triedy:

Collection syncedCollection = Collections.synchronizedCollection (originalCollection); Set syncedSet = Collections.synchronizedSet (nový HashSet ()); Zoznam unmodifiableList = Collections.unmodifiableList (originalList); Mapa unmodifiableMap = Collections.unmodifiableMap (originalMap); 

Počet statických továrenských metód v JDK je skutočne rozsiahly, takže zoznam príkladov z dôvodu stručnosti udržíme krátky.

Vyššie uvedené príklady by nám napriek tomu mali poskytnúť jasnú predstavu o tom, aké všadeprítomné statické továrenské metódy sú v Jave.

4. Vlastné statické výrobné metódy

Samozrejme, môžeme implementovať naše vlastné statické továrenské metódy. Kedy to však naozaj stojí za to, namiesto vytvárania inštancií tried pomocou obyčajných konštruktorov?

Pozrime sa na jednoduchý príklad.

Považujme to za naivné Používateľ trieda:

verejná trieda Používateľ {private final Názov reťazca; súkromný záverečný reťazcový e-mail; súkromná konečná reťazcová krajina; public User (meno reťazca, e-mail reťazca, krajina reťazca) {this.name = meno; this.email = e-mail; this.country = country; } // štandardné getre / toString}

V tomto prípade neexistujú žiadne viditeľné varovania, ktoré by naznačovali, že statická továrenská metóda môže byť lepšia ako štandardný konštruktor.

Čo ak to chceme všetko Používateľ inštancie dostanú predvolenú hodnotu pre krajina lúka?

Ak inicializujeme pole s predvolenou hodnotou, museli by sme tiež rekonštruovať konštruktor, čím by bol návrh rigidnejší.

Namiesto toho môžeme použiť statickú továrenskú metódu:

public static User createWithDefaultCountry (názov reťazca, reťazcový e-mail) {vrátiť nového používateľa (meno, e-mail, "Argentína"); }

Takto by sme dostali Používateľ inštancia s predvolenou hodnotou priradenou k krajina lúka:

User user = User.createWithDefaultCountry ("John", "[chránený e-mailom]");

5. Presun logiky z konštruktérov

Náš Používateľ trieda by mohla rýchlo zmeniť na chybný dizajn, ak by sme sa rozhodli implementovať funkcie, ktoré by vyžadovali pridanie ďalšej logiky do konštruktora (do tejto doby by už mali znieť poplašné zvony).

Predpokladajme, že chceme poskytnúť triede schopnosť zaznamenávať čas, kedy každý Používateľ objekt je vytvorený.

Keby sme túto logiku vložili do konštruktora, porušili by sme princíp jednej zodpovednosti. Skončili by sme s monolitickým konštruktorom, ktorý robí oveľa viac ako inicializuje polia.

Náš dizajn môžeme udržať čistý pomocou statickej továrenskej metódy:

verejná trieda Používateľ {private static final Logger LOGGER = Logger.getLogger (User.class.getName ()); súkromné ​​konečné meno reťazca; súkromný záverečný reťazcový e-mail; súkromná konečná reťazcová krajina; // štandardné konštruktory / getre verejné statické User createWithLoggedInstantiationTime (názov reťazca, e-mail reťazca, krajina reťazca) {LOGGER.log (Level.INFO, "Vytváranie inštancie používateľa na adrese: {0}", LocalTime.now ()); vrátiť nového používateľa (meno, e-mail, krajina); }} 

Takto by sme vytvorili naše vylepšené Používateľ inštancia:

Používateľ user = User.createWithLoggedInstantiationTime ("John", "[chránený e-mailom]", "Argentína");

6. Instancia riadená inštanciou

Ako je uvedené vyššie, môžeme zapuzdriť bloky logiky do statických továrenských metód pred návratom úplne inicializovaných Používateľ predmety. Môžeme to urobiť bez toho, aby sme znečisťovali konštruktéra zodpovednosťou za vykonávanie viacerých, nesúvisiacich úloh.

Napríklad Predpokladajme, že chceme, aby sa naše Používateľ triedy a Singleton. Môžeme to dosiahnuť implementáciou inštancie riadenej statickej továrenskej metódy:

verejná trieda User {private static volatile User instance = null; // ďalšie polia / štandardné konštruktory / getre verejné statické Používateľ getSingletonInstance (názov reťazca, reťazec e-mail, krajina reťazca) {if (instance == null) {synchronizovaný (User.class) {if (instance == null) {instance = nový Používateľ (meno, e-mail, krajina); }}} návratová inštancia; }} 

Vykonávanie getSingletonInstance () metóda je bezpečné pre vlákna, s malou penalizáciou výkonu, kvôli synchronizovanému bloku.

V tomto prípade sme použili lenivú inicializáciu na demonštráciu implementácie inštanciou riadenej statickej továrenskej metódy.

Za zmienku však stojí, že najlepší spôsob implementácie Singletonu je pomocou Java enum typu, pretože je bezpečný aj pre serializáciu, aj pre vlákna. Podrobné informácie o tom, ako implementovať Singletons pomocou rôznych prístupov, nájdete v tomto článku.

Ako sa dalo čakať, získanie a Používateľ objekt s touto metódou vyzerá veľmi podobne ako predchádzajúce príklady:

Používateľ user = User.getSingletonInstance ("John", "[chránený e-mailom]", "Argentína");

7. Záver

V tomto článku sme preskúmali niekoľko prípadov použitia, kedy môžu byť statické továrenské metódy lepšou alternatívou k použitiu obyčajných konštruktorov Java.

Navyše, tento model refaktoringu je tak pevne zakorenený v typickom pracovnom postupe, že to väčšina IDE urobí za nás.

Samozrejme, Apache NetBeans, IntelliJ IDEA a Eclipse vykonajú refaktoring mierne odlišnými spôsobmi, takže si najskôr skontrolujte dokumentáciu k IDE.

Rovnako ako v prípade mnohých ďalších vzorov refaktoringu, mali by sme statické továrenské metódy používať s náležitou opatrnosťou a iba vtedy, ak stojí za kompromis medzi výrobou flexibilnejších a čistejších návrhov a nákladmi na implementáciu ďalších metód.

Ako obvykle sú všetky ukážky kódu zobrazené v tomto článku k dispozícii na GitHub.


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