Double Dispatching
Double Dispatching je OOP design pattern používaný v Smalltalku a iných objektovo-orientovaných jazykoch na elegantné riešenie problému polymorfizmu s parametrami.
Problém?
Ten nastáva v prípade, ak objektu pošleme správu s istým stupňom neurčitosti (voľnosti). Napríklad prienik s nejakým objektom alebo pripočítanie k nejakému číslu. Vtedy na spracovanie správy potrebujeme určiť, kto sa za parametrom skrýva.
Ak pošleme objektu správu s parametrom, výsledné správanie je definované nejakou prislúchajúcou metódou v príjemcovi správy. Niekedy je správanie podmienené typom, či triedou parametra. V niektorých jazykoch, ktoré podporujú case konštrukcie (C++, Java,...) by jedným z možných riešení mohlo byť rozhodnúť sa (v case) podľa typu parametra. V Smalltalku však žiadne case, či switch nemáme. Ak sa pridá nová trieda pre parameter, museli by sme modifikovať kvantum if-ov.
Riešenie
Spočíva v postupnom znižovaní stupňa neurčitosti. V Smalltalku je lepšie použiť polymorfickú prirodzenosť jazyka a použiť techniku známu ako Double Dispatching. Tá zahŕňa pridanie druhej metódy (secondary method) všetkým triedam potenciálnym parametrom a potom jej zavolaním z pôvodnej metódy s prijímateľom ako parameter.
Jednou veľmi peknou vlastnosťou Double Dispatchingu je, že kompletne nahradzuje podmienkové konštrukcie pre robustnejší kód. Polymorfický dispatching sa postará o rozhodnutia.
Použitie
Použitie vysvetlíme na príklade. Konkrétne použijeme definíciu tried a metód, použitých v SmallTalku na hierarchii tried počínajúc Number.
Trieda Integer a jej podtriedy používajú double dispatch na implementovanie niektorých základných aritmetických operácií. Ukážeme si na operácii (metóde) #+ (plus).
#+ je definované Integerom takto:
^aNumber addToInteger: self
Vnútri tejto metódy, už vieme, že aNumber sa chce pripočítať k príjimateľovi (to akože Integeru). Aby sme predišli písaniu kódu, ktorý by sa rozhodoval podľa parametra aNumber, môžeme jednoducho požiadať aNumber, aby tento výpočet spravil za nás.
^anInteger retry: #+ coercing: self
Každá podtrieda Integeru, ktorá požaduje špeciálne pripočítavnie, implementuje svoju vlastnú #addToInteger. Napríklad trieda Fraction class vie, ako si má k sebe ten Integer pripočítať:
^Fraction
numerator: anInteger denominator + numerator denominator: denominator
V podstate takto môžeme rozdeliť metódy na tri druhy:
- primárne operácie
- double dispatching metódy
- forward metódy
Výhody
Koľko to stojí?
Pridanie novej triedy takto znamená pridanie správy do každej z ostatných tried, v najhoršom prípade N2 metód pre N tried. Napriek tomu, celkový počet riadkov kódu sa nám viditeľne nezväčší.
Porovnanie (36 tried, 5 operátorov):
| predtým | DD bez redukcie | DD s redukciou | |
|---|---|---|---|
| základné metódy | 180 | 180 | 180 |
| korekcie | 73 | 0 | 0 |
| Double Dispatch | 0 | 6480 | 221 |
| Celkový počet | 253 | 6660 | 401 |


