C# týden Slevový týden - Březen
Využij náš slevový týden a získej až 30 % bodů navíc zdarma! Zároveň také probíhá C# týden se slevou na e-learning až 80 %
Hledáme fulltime programátora do ITnetwork týmu -100% homeoffice, 100% časově flexibilní #bezdeadlinu Mám zájem!

Factory (továrenské metóda)

Factory (alebo tiež po slovensky "faktorka") je jeden z najdôležitejších návrhových vzorov, ktorý umožňuje vyššiu abstrakciu pri vytváraní triedy než klasický konštruktor. Typicky sa používa pre zapuzdrenie zložitejšie inicializácia inštancie a pre vytváranie rôznych typov inštancií podľa reťazca.

Motivácia

V aplikáciách sa nám občas stáva, že potrebujeme vytvoriť inštanciu nejaké triedy a tú dodatočne inicializovať. Dobrým praktickým príkladom sú formulárové komponenty, u ktorých nestačí iba inštanciu vytvoriť, ale musíme ju tiež nastaviť veľa ďalších vlastností (rozmery, titulok, pozíciu, farbu ...). Ak niekde v aplikácii vytvárate 20 podobných tlačidiel a vytvorenie takéhoto tlačidla zaberá 10 riadkov, nutne vás napadne oddeliť tento kód do metódy. Gratulujem, práve ste vynašli factory. (Samozrejme má vzor nejaké ďalšie konvencie)

Faktorka môže tiež uchovávať premenné, ktoré potrebujeme k vytváraniu inštancií. Tieto premenné potom nemusí prestupovať celú aplikácií. Ďalšou výhodou je návratový typ, ktoré nemusia byť u faktorky špecifikovaný presne na typ objektu, ktorý vytvárame. Môžeme vracať niektorú z rodičovských tried alebo aj rozhranie. Na každý z týchto prípadov sa pozrieme bližšie.

Vzor sa nachádza v rôznych podobách a existujú aj jeho ďalšie variácie (factory, abstract factory, factory method, simple factory) a rôzne materiály je často vykladajú rôznym spôsobom. Základná myšlienka je však vždy rovnaká.

Factory Method

Návrhový vzor Factory method využíva metódy volajúci konštruktor. Má pomerne veľa rôznych podôb, niekedy môže byť použité dedenia a väčšinou sa píše proti rozhranie. My si tu ukážeme úplne najjednoduchšie implementáciu. Kľúčové je oddelenie konštrukcie konkrétnej inštancie do inej triedy, čím sa pôvodná trieda neznečistí konštrukčným kódom.

class Auto
{
    private string znacka;
    private string model;

    public Auto(string znacka, string model)
    {
        this.znacka = znacka;
        this.model = model;
    }

}

class TovarnaNaAuta
{
    public Auto VytvorFelicii()
    {
        return new Auto("Škoda", "Felicia");
    }
}

Máme tu jednoduchú triedu s verejným konstruktoru. Samozrejme môžeme tvoriť konkrétne inštancie automobilov:

Auto fabia = new Auto("Škoda", "Fabia");
Tento výukový obsah pomáhajú rozvíjať nasledujúce firmy, ktoré možno hľadajú práve teba!

Keďže v našej aplikácii často tvoríme Felicie alebo pre nás majú skrátka nejaký vyšší význam a zároveň nechceme zasahovať do triedy Auto, je ich konštrukcia zjednodušená na obyčajné zavolanie metódy továrenské triedy:

TovarnaNaAuta tovarna = new TovarnaNaAuta();
Auto felicia = tovarna.VytvorFelicii();

Keď si predstavíte, že Felicie má automaticky nastavených napr. 30 atribútov, tak sa vzor určite oplatí. A aj keby sme Feliciu potrebovali len na jednom mieste v programe, oddelení zložité inicializácia do inej triedy sprehľadní ďalšie logiku v triede, kde inštanciu potrebujeme.

Factory

Všeobecnejšom návrhom je Factory. V princípe sa jedná opäť o Factory Method, pretože to musí byť opäť metóda, ktorá našu inštanciu vytvára. Tu sú požiadavky omnoho voľnejšie. Metóda môže byť definovaná ako statická (niekedy aj v tej istej triede, s tým sa stretávame typicky u Javy). Ukážme si ďalší príklad:

class Auto
{
    private string znacka;
    private string model;

    private Auto(string znacka, string model)
    {
        this.model = model;
        this.znacka = znacka;
    }

    public static Auto Felicia()
    {
        return new Auto("Škoda", "Felicia");
    }
}

V tomto variante vzoru sa inštancie triedy nedá vytvoriť žiadnym iným spôsobom, než továrenské metódou (ale samozrejme môže byť konštruktor i verejný).

Inštanciu vytvoríme ako:

Auto felicia = Auto.Felicia();

Výhodou statické metódy priamo v triede je jednoduchšie implementácia. Samozrejme by sme ich nemali mať v triede moc a mali by byť nejako viazané na pôvodnú funkcionalitu triedy, inak by mali byť v samostatnej triede. Asi najsprávnejším príkladom takejto statickej metódy je získanie aktuálneho dátumu a času v C # .NET:

DateTime listopad = new DateTime(2018, 11, 24); // Konkrétní datum
DateTime dnes = DateTime.Now();

Metóda Now() vráti inštanciu DateTime, inicializuje na aktuálny dátum a čas. Takáto metóda priamo súvisí s funkcionalitou DateTime a preto je navrhovať správne, že je v tejto triede a aj statika tu dáva zmysel. Naopak, u našej Felicie() je to skôr odstrašujúci príklad, pretože s všeobecnou triedou Auto príliš nesúvisí.

Pozn .: VC # .NET je Now() vlastnosť, ktorá sa od metódy v nejakých detailoch odlišuje, v príklade bola uvedená ako metóda, aby zbytočne nezmátla programátorov v iných jazykoch.

Vytváranie inštancií rôznych tried

Návratová hodnota nemusí byť u Faktory rovnaká, ako je typ vytváranej inštancie. Pokojne môžeme vytvárať pri každom volaní inštanciu iné typ triedy a vracať iba rozhranie, ktoré všetky triedy implementujú. Ako príklad uvediem grafický program, ktorý vykresľuje rôzne obrazce na obrazovku. Povedzme teda, že máme štvorec, kruh a trojuholník, ktoré všetky implementujú rozhranie IVykreslitelny. Dáta získavame z reťazca (napr. Dekóduje nejaký textový súbor). Podľa dodaných dát sa rozhodneme, ktorý typ tvaru vytvoriť a vrátime ho iba ako rozhranie. Samotný program nevie, čo je to za obrazec. Iba vie, že ho možno vykresliť.

interface IVykreslitelny
{
    void Vykresli();
}

class Ctverec : IVykreslitelny { /* ... Kód ... */ }
class Trojuhelnik : IVykreslitelny { /* ... Kód ... */ }
class Kruh : IVykreslitelny { /* ... Kód ... */ }

class TvarFactory
{
    public IVykreslitelny Vytvor(string typ)
    {
        if (typ == "Ctverec")
            return new Ctverec();
        else if (typ == "Trojuhelnik")
            return new Trojuhelnik();
        else if (typ == "Kruh")
            return new Kruh();
    }
}

// použití v programu
Factory faktorka = new TvarFactory();
IVykreslitelny instance = faktorka.Vytvor("Ctverec");

Vidíme, že typ sa mení. Jediné, čo program vie, je, že možno objekt vykresliť, ale už nič o tom ako sa vykreslí. To by ho však nemalo ani zaujímať, pretože by sa o vykreslenie starať nemal. Buď sa o vykreslenie stará opäť konkrétna trieda alebo samotnej objekty.

Ak by tvarov bolo viac typov, je výhodnejšie použiť reflexiu a dynamicky vytvárať inštancie tried, ktorých názov korešponduje s názvom tvaru. Nesmieme tu zabudnúť nejako ošetriť, aby bolo vytváranie tried obmedzené na určitý balík, inak by si užívateľ mohol vytvoriť prakticky čokoľvek z našej aplikácie.

Návrhový vzor Factory

Závislosť na parametroch

Niekedy potrebujeme vytvoriť inštanciu triedy, ale parametre pre konštruktor získame na inom mieste v programe. Konštruktor využiť nemôžeme, pretože ešte nepoznáme všetky parametre a vytvoriť neinicializované inštanciu napr. Bezparametrickým konstruktoru nie je dobrá praktika. Ak využijeme Factory triedu, môžeme jej dáta postupne odovzdávať a ona si ich bude uchovávať. Vo chvíli, keď dát bude dostatok, môžeme inštanciu vytvoriť. Nemusíme sa teda starať o žiadne odovzdávanie dát medzi časťami programu, odovzdáme iba inštanciu triedy Factory.

Do tohto článku bude postupne doplňovaná ďalšie implementácie rôznych typov továrniček. Chcete nám pomocou svojou skúsenosťou s factory? Napíšte nám do komentárov.


 

 

Článok pre vás napísal Patrik Valkovič
Avatar
Ako sa ti páči článok?
Ešte nikto nehodnotil, buď prvý!
Věnuji se programování v C++ a C#. Kromě toho také programuji v PHP (Nette) a JavaScriptu (NodeJS).
Všetky články v sekcii
GOF - Vzory pre vytváranie
Aktivity (1)

 

 

Komentáre

Avatar
Jan Vargovský
Redaktor
Avatar
Jan Vargovský:24.11.2015 20:06

To je method chaining pattern.

 
Odpovedať
24.11.2015 20:06
Avatar
Milan Křepelka
Redaktor
Avatar
Milan Křepelka:24.11.2015 20:19

To je fluent interface. Lehce mimo záběř vytváření instancí. Navíc továrny mají šetřit práci a tohle mi teda moc nepřipadá. ;-)

 
Odpovedať
24.11.2015 20:19
Avatar
Honza Bittner
Šupák
Avatar
Odpovedá na Milan Křepelka
Honza Bittner:24.11.2015 23:56

Koukám, že jsem si to zaměnil kvůli podobnosti. Googlil jsem si to a to, co jsem psal je označováno jako Builder.

Co jsem pochopil z googlení (např. http://stackoverflow.com/…7761/3281252) tak Factory umožní použít předpřipravené "nastavené" objektu. Oproti tomu Builder umožní jednoduché/přeh­ledné vytváření vlastního nastavení objektu.

Odpovedať
24.11.2015 23:56
Student FIT ČVUT. In love with Dart &...
Avatar
Richard H.
Redaktor
Avatar
Richard H.:28.11.2015 23:01

Pěkný článek konečně mi došlo k čemu my je Factory.

Odpovedať
28.11.2015 23:01
Malý užitečný manuál je vždy lepší než bichle k ničemu.
Avatar
Erik Báča
Člen
Avatar
Erik Báča:13.4.2016 21:46

Proč je v těch ukázkách pořád string, místo String? Je to tam tolikrát, že to asi chyba není, ale nechápu to :D

Odpovedať
13.4.2016 21:46
Když mi dáš mínus, napiš proč!
Tento výukový obsah pomáhajú rozvíjať nasledujúce firmy, ktoré možno hľadajú práve teba!
Avatar
Taskkill
Redaktor
Avatar
Odpovedá na Erik Báča
Taskkill:13.4.2016 22:39

v c++ je to treba string, v Jave String v jS String atd ... ale rekl bych, ze nekdo ma navyk pouzivat string v pseudokodu... je to o preferenci rekl bych

 
Odpovedať
13.4.2016 22:39
Avatar
Erik Báča
Člen
Avatar
Odpovedá na Taskkill
Erik Báča:13.4.2016 22:46

Aha, díky

Odpovedať
13.4.2016 22:46
Když mi dáš mínus, napiš proč!
Avatar
Odpovedá na Erik Báča
Patrik Valkovič:13.4.2016 23:17

v C# je string.

Odpovedať
13.4.2016 23:17
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
dave_23
Redaktor
Avatar
dave_23:14.6.2016 14:22

Neměla by u Vytváření instancí různých tříd být metoda Vytvor() statická? Následující příklad použití v programu tomu totiž nasvědčuje.

 
Odpovedať
14.6.2016 14:22
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovedá na dave_23
David Čápka:25.9.2017 10:32

Tam jen má být malé f, opravil jsem to :)

Odpovedať
25.9.2017 10:32
Jsem moc rád, že jsi na síti, a přeji ti top IT kariéru, ať jako zaměstnanec nebo podnikatel. Máš na to! :)
Robíme čo je v našich silách, aby bola tunajšia diskusia čo najkvalitnejšia. Preto do nej tiež môžu prispievať len registrovaní členovia. Pre zapojenie sa do diskusie sa zaloguj. Ak ešte nemáš účet, zaregistruj sa, je to zadarmo.

Zatiaľ nikto nevložil komentár - buď prvý!