Object Pool (česky fond nebo též bazén) je jeden z mnoha návrhových vzorů. Využijeme ho ve chvíli, kdy potřebujeme z nějakého důvodu omezit počet vytvořených instancí a místo vytváření nových instancí dáme přednost „reinkarnaci“ (znovuoživení) instancí dříve použitých a v danou chvíli nepoužívaných. [1]

Class diagram

Účel editovat

Návrhový vzor fond uplatníme v případě, pokud potřebujeme větší množství instancí, které jsou časově náročné na vytvoření, ale nepotřebujeme jich mnoho zároveň. Namísto neustálé tvorby nových instancí použijeme ty, které jsme vytvořili již dříve a nyní nejsou nikým používané.

Popis fondu editovat

Abstrakce editovat

Pokud bychom si při pochopení návrhového vzoru fond chtěli pomoct abstrakcí z reálného světa, mohli bychom ho přirovnat k půjčovně kostýmů. Vyrobit si kostým je časově náročné, proto si raději nějaký vypůjčíme. Zároveň ho zpravidla chceme na jednorázové použití a bylo by hloupé ho vyhodit, když nám dal takovou práci. Jako ideální řešení se tedy jeví si ho vypůjčit.
V půjčovně mají kostýmy hotové a ihned k dispozici. Když už kostým nepotřebujeme, vrátíme ho zpět. V půjčovně ho vyperou nebo opraví a připraví k dalšímu použití pro ostatní. Pokud by náhodou kostýmy došly, umí si většinou půjčovna vyrobit nové. V opačném případě musíme počkat, než kostým někdo vrátí.

Popis editovat

Fond si lze představit jako množinu objektů, které jsou vytvořeny a připraveny k použití. Neplatí tedy obvyklý životní cyklus objektu, kdy je vytvořen až v okamžiku potřeby a po vykonání operací zahozen. V tomto případě si klient vyžádá připravený objekt přímo z fondu, provede s ním požadované operace a následně ho vrátí zpět.
Takovéto skladování objektů může značně zvýšit výkon v situacích, kdy je inicializace objektu náročná, my je přesto potřebujeme často vytvářet a přitom nám v jich v daném čase stačí mít k dispozici málo. Nespornou výhodou je, že si objekty můžeme dopředu připravit. Toto se zvláště hodí pro síťové aplikace, kde se dá stěží odhadnout čas na inicializaci objektu. Jako možný případ využití lze považovat navázání spojení s databází nebo s portem, velké grafické objekty nebo vlákna.
Pro jednoduché objekty nemusí být tento postup efektivní, neboť je zbytečně udržujeme v paměti. Moderní programovací jazyky, které obsahují garbage collector, nemají problém s vytvářením a následným zahazováním nenáročných objektů.

Typy fondu editovat

Existuje několik typů fondů. Liší se v chování, pokud neobsahují žádný volný objekt.

  • Fond objekt jednoduše neposkytne, neboť ani nemá jaký, a vrátí chybu (způsobí výjimku).
  • Fond s proměnou kapacitou - vytvoří nový objekt a rozšíří tak velikost fondu.
  • Fond s omezenou kapacitou - klient musí počkat, než někdo jiný vrátí objekt zpět do fondu. Toto je možné pouze ve vícevláknovém prostředí.

Fond s proměnou kapacitou editovat

Fond dynamicky zvyšuje počet instancí. Předpokládá se, že jejich celkový počet zůstane stále rozumně malý. To může vyplývat přímo z povahy aplikace nebo je počet omezen pro jistotu nějakou podmínkou. Uplatníme ho tehdy, kdy si nemůžeme dovolit čekat na vytvoření instance, například jednotlivá vlákna starající se o animaci.

Fond s omezenou kapacitou editovat

Fond má předem daný maximální počet instancí, se kterými může disponovat. Pokud je prázdný, požadavky na vydání instance se řadí do fronty. Klient musí počkat, než instanci uvolní někdo jiný. Typickým příkladem je připojení k databázi. Navázání připojení může trvat i několik sekund a větší počet současných připojení zpomaluje práci s databází.

Z toho zároveň vyplývá, že fond musí být schopen vytvářet nové instance třídy, jejíž objekty v sobě uchovává. Dále fond bývá často definován jako jedináček (singleton), to znamená, že současně může existovat pouze jedna jeho instance.

Možné problémy editovat

Fond musí zajistit, že navrácený objekt bude „resetován“. Tím je myšleno, že stavy objektu budou nastaveny na výchozí hodnoty a objekt tak nebude ohrožovat uživatele fondu neočekávaným chováním. Fondy (bazény) obsahující takovéto nebezpečné objekty jsou občas nazývány žumpami.
Příkladem muže být objekt, který reprezentuje přihlášení. Pokud bychom neresetovali hodnotu „úspěšně přihlášen“, mohl by jiný uživatel být přihlášen jako někdo jiný, aniž by se sám o přihlášení vůbec pokusil. Nebezpečí také spočívá v úniku informací. Objekt může obsahovat důvěrná data, která by se takto mohla dostat do rukou cizí osoby.
Není důležité vždy resetovat všechny hodnoty.

Příklad využití editovat

Představme si webový katalog, který umožňuje prohlížet a objednávat zboží. Většina stránek katalogu je dynamicky generována na základě dat z databáze. Pokud si chceme takovou stránku prohlédnout, katalog musí nejprve sáhnout do databáze. Toto se děje velmi často, například každé prohlédnutí konkrétního zboží, přechodu na další stránku s položkami atd. A pro každý takovýto požadavek by katalog musel navázat nové připojení. Ovšem takovéto řešení by bylo nanejvýš neefektivní, neboť by docházelo k časovým prodlevám při každém navázání spojení. Zároveň by byl zpomalen celý systém, protože by takovýchto požadavků musel vyřizovat třeba tisíce ve velmi krátkém čase. V tomto případě se jako optimální řešení nabízí využít právě fond, který se bude o připojení k databázi starat. [2]

Implementace editovat

Fond s dynamicky se měnícím počtem instancí editovat

Takovýto fond musí implementovat dvě metody – metodu pro uložení instance do fondu a metodu pro její zpětné vyzvednutí. V případě, že je fond prázdný, tato metoda musí vytvořit instanci novou. Počet instanci by měl přesto zůstat přijatelně nízký, případně být ošetřen nějakou podmínkou vyhazující výjimku.
Objekty uložené ve fondu je vhodné si ukládat do nějakého dynamického kontejneru (např. seznamu nebo množiny). Jedním z možných způsobů je použít princip zásobníku. Každý navrácený objekt uložit na konec seznamu a při žádosti o vydání objektu vracet opět ten poslední a zároveň ho ze seznamu odstranit.

Fond s omezenou maximální kapacitou editovat

Pokud jsem se rozhodli pro fond s omezeným maximálním počtem instancí, je možné si jednotlivé instance ukládat do nějakého statického pole. Pro malý počet prvků stačí vyhledávat v poli obyčejnou iterací, pro větší množství je vhodná například hashmapa. Fond musí poskytovat opět metodu pro uložení instance a metodu pro její zpětné navrácení. Na rozdíl od dynamického fondu ale nemůže vytvořit novou instanci (pokud je dosaženo maximální kapacity), nýbrž musí požadavek zařadit do fronty a čekat, dokud někdo nevrátí volnou instanci zpět do fondu.

Ukázky editovat

Následující ukázky jsou v jazyce Java. Jedná se o rozhraní (interface) pro generické fondy (využívají parametrizované typy) – o tom, jaké objekty budou uchovávat, se rozhodne až v okamžiku jejich vytvoření.

Rozhraní pro dynamický fond editovat

/**
 * Generické rozhraní pro fond s dynamickým počtem instancí.
 * Fond implementující toto rozhraní se rozhodne, jaké objekty
 * bude uchovávat až při svém vzniku.
 */
public interface IDynamickyFond<T> {
    /*
     * Vyzvedne z fondu volnou instanci a vrátí ji, pokud není žádná
     * k dispozici, vytvoří se nová.
     * @return T znovupoužitelná instance
     */
    public T dejNeboVytvor();

    /*
     * Vrátí do fondu instanci, která již není nikým používána.
     * Tímto ji poskytne zpět k novému použití.
     * @param vracená znovupoužitelná  instance
     */
    public void vracimZpet(T instance);
}

Rozhraní pro kapacitně omezený fond editovat

/**
 * Generické rozhraní pro fond s omezeným maximálním počtem instancí.
 */
public interface IOmezenyFond<T> {
    /*
     * Vyzvedne z bazénu volnou instanci a vrátí ji, pokud není žádná
     * k dispozici, zařadíme se do fronty čekatelů a musíme vyčkat než
     * se nějaká uvolní.
     * @return T znovupoužitelná instance
     */
    public T dejNeboPockam();

    /*
     * Vrátí do fondu instanci, která již není nikým používána.
     * @param vracená znovupoužitelná  instance
     */
    public void vracimZpet(T instance);
}

Továrna na objekty editovat

/**
 * Generické rozhraní pro univerzální továrnu na objekty, které budeme
 * skladovat ve fondu.
 */
public interface ITovarna<T> {

    /*
     * Vytvoří novou instanci a vrátí na ni odkaz.
     * @return T nová instance
     */
    public T vytvorNovou();
}

Reference editovat

  1. PECINOVSKÝ, Rudolf. Návrhové vzory. Brno: ComputerPress, 2007. ISBN 978-80-251-1582-4. Kapitola 12. 
  2. Michael Kircher, Prashaint Jaint; PRASHANT JAIN. Pooling [online]. [cit. 2009-11-02]. Dostupné online. (anglicky) 

Související články editovat

Externí odkazy editovat