Dynamické správanie

Dynamické proxy

Priamo v štandardnej knižnici je nástroj na dynamické vytváranie nových tried, ktorý sa nazýva dynamické proxy. Je inšpirovaný návrhovým vzorom Proxy a umožňuje realizovať tento návrhový vzor. Možnosti využitia dynamického proxy sú však oveľa širšie.

Dynamické proxy je realizované triedou Proxy a umožňuje vytvorenie novej triedy implementujúcej zadané rozhrania priamo počas behu programu.

Statická metóda getProxyClass nám vráti vytvorenú triedu, ktorá implementuje všetky metódy definované rozhraniami, ktoré tejto metóde odovzdáme. Následne môžeme vytvoriť inštanciu proxy-triedy pomocou konštruktora, ktorý očakáva jeden argument — objekt implementujúci rozhranie InvocationHandler. Danému objektu budú odovzdávané na spracovania všetky volania metód proxy-objektu.

Class c = Proxy.getProxyClass(SomeInterface.class.getClassLoader(), SomeInterface.class);
Constructor cons = c.getConstructor(InvocationHandler.class);
Object proxy = cons.newInstance(new SomeIH(obj));

Pokiaľ potrebujeme iba jeden proxy-objekt, môžeme použiť metódu newProxyInstance:

Object proxy = Proxy.newProxyInstance(
    SomeInterface.class.getClassLoader(),
    new Class[]{ SomeInterface.class },
    new SomeIH(obj));

Rozhranie InvocationHandler definuje jedinú metódu:

Object invoke(Object proxy, Method method, Object[] args) throws Throwable

Táto metóda je volaná vždy, keď sa volá metóda na proxy-objekte a jej parametrami sú

  • samotný proxy-objekt,
  • metaobjekt reprezentujúci volanú metódu,
  • pole argumentov, s ktorými bola metóda zavolaná.

InvocationHandler môže vykonať akúkoľvek činnosť v reakcii na volanie metódy. Ak však má realizovať vzor Proxy, potom pravdepodobne bude volať danú metódu na nejakom cieľovom objekte, ktorý proxy zastupuje:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    return method.invoke(target, args);
}

V tomto prípade volanie metódy je možné znázorniť pomocou sekvenčného diagramu, na ktorom je vidieť, ako sa riadenie postupne odovzdáva od Proxy cez InvocationHandler až k cieľovému objektu.

Volanie metódy nad proxy. Zdroj: Ira R. Forman, Nate Forman. Java Reflection in Action
Obr. 1: Volanie metódy nad proxy. Zdroj: Ira R. Forman, Nate Forman. Java Reflection in Action

InvocationHandler však môže túto reťaz prerušiť a nahradiť vykonanie cieľovej metódy nejakou inou operáciu, alebo ju iba doplniť.

Dynamické proxy je, samozrejme, možné použiť na realizáciu všetkých typov vzoru Proxy. Je tiež vhodný na doplnenie funkcionality do metód existujúcej triedy (vzor „decorator“) ale aj na úplné nahradenie skutočného objektu (napr. „mock objekty“). Ďalšie informácie a príklady si pozrite v článku Briana Goetza Decorating with dynamic proxies.

Zdroje