V sobotu 2. listopadu proběhla mohutná oslava naší plnoletosti !!
Multimediaexpo.cz je již 18 let na českém internetu !!

Lazy loading

Z Multimediaexpo.cz

Lazy Loading je návrhový vzor pro strategii načítání objektů z databáze až v momentě, kdy jsou opravdu potřeba. Tato strategie je velice důležitá při zlepšování výkonu aplikací pracujících s databází. V programování je častým problémem nahrávání entit, které jsou spojené s velikým množstvím jiných entit a tudíž nahrání takové entity vede k nahrání všech těchto spojených entit, čímž se výkon aplikace razantně snižuje. Lazy Loading toto řeší řízením dotazů do databáze, které jsou prováděny až v momentě, kdy jsou data spojená s nahrávanou entitou opravdu zapotřebí. Je však zbytečné tento postup aplikovat, pokud data, která potřebujeme jsou všechny v jedné tabulce databáze. Jinými slovy je Lazy Loading užitečný tehdy, když na nahrání celé entity se všemi daty (i s těmi napojenými na entitu) je potřeba více dotazů do několika tabulek databáze najednou.

Obsah

Druhy Lazy Loadingu

Existují 4 základní postupy implementace této strategie, jsou to Lazy initialization, Virtuální proxy, Value holder a Ghost.

Lazy initialization

Lazy initialization je nejjednodušší způsob implementace Lazy Loadingu. Funguje na způsobu kontrolování požadované proměnné, která je nahrávána z databáze, na hodnotu null. Toto souvisí s důležitostí jednoho z pravidel objektově orientovaného programování - zapouzdření. Pokud bychom nepřistupovali k proměnné přes její přístupovou metodu, nebylo možné lazy initialization implementovat.

Ukázka Lazy initialization

class Supplier... {
  public List getProducts() {
    if (products == null) products = Product.findForSupplier(getID());
      return products;
    }
  }
}

Z ukázky je patrné, jak Lazy initialization funguje. Pokud se aplikace dotáže na proměnnou products, je zavolána přístupová metoda getProducts(). Zde je kontrola na hodnotu null. Pokud je daný objekt null, znamená to, že nebyla inicializována a je potřeba ji načíst z databáze.

Virtuální proxy

Virtuální proxy je implementace Lazy Loadingu nahrazením entity jejím virtuálním dvojníkem, který prakticky neobsahuje žádné data, ale implementuje stejné rozhraní jako originální objekt. Načítání a vracení požadovaných dat je prováděno až v momentě, kdy je zavolána patřičná metoda proxy objektu. Důležité je poznamenat, že virtuální je v podstatě originální objekt, neboť objekt, který ten originální obaluje bude v aplikaci vždy dostupný, kdežto obalený (originální) objekt nemusí být vůbec inicializován a tudíž dostupný. Velikou výhodou této implementace je možnost existence více proxy objektů pro jeden reálný objekt. Nevýhodou je však nutnost vytváření proxy objektů pro každý objekt, pro který chceme zavést Lazy loading.

Ukázka virtuální proxy

Class VirtualList implements List { 
  private List source;
  private VirtualListLoader loader;
  public VirtualList(VirtualListLoader loader) {
    this.loader = loader;
  }
  private List getSource() {
    if (source == null) source = loader.load();
      return source;
    }
  }
  public int size() {
    return getSource().size();
  }
}

V ukázce je proměnná source originálním objektem, který obaluje třída VirtualList. Pokud v aplikaci potřebujeme znát velikost kolekce List (proměnná source), zavoláme metodu getSize(), která nejdříve zkontroluje, zda je proměnná source inizializována a pokud tomu tak není, načte ji z databáze. Dále je pak zavolána metoda size() již na originálním objektu. Zde je patrné, že je potřeba implementovat všechny metody originálního objektu, které chceme mít přístupné.

Value holder

Value Holder je velice podobný Virtuální proxy, používá se však většinou v případě, kdy je potřeba generika. Sám ValueHolder se stará o Lazy Loading. K získání hodnoty obaleného objektu je volána metoda getValue(), která přistupuje k databázi pouze poprvé, kdy je tato metoda volána, dále už jen vrací inicializovaný objekt.

Ukázka Value Holderu

class SupplierVH... {
  private ValueHolder products;
  public List getProducts() {
    return (List) products.getValue();
  }
}
class ValueHolder... {
  private Object value;
  private ValueLoader loader;
  public ValueHolder(ValueLoader loader) {
    this.loader = loader;
  }
  public Object getValue() {
    if (value == null) {
      value = loader.load();
    }
    return value;
  }
}

Ghost

Ghost, neboli duch, je implementace Lazy loadingu, kdy reálný objekt existuje jen v částečném stavu. Po načtení z databáze obsahuje pouze ID. Až v případě, že je potřeba získat další data tohoto objektu, je plně načten z databáze a inicializován. V podstatě se jedná o objekt, kdy každá proměnná tohoto objektu je inicializována v jednom momentě do plného stavu.