Double Dispatching
oop design patternObsah
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, samozrejme, je správanie podmienené typom, či triedou parametra. V niektorých jazykoch, ktoré svojím spôsobom 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 a pre výsledok zavolať inú metódu. V Smalltalku však žiadne case, či switch nemáme. Tam sa na nás tak maximálne uškŕňajú ifTrue:ifFalse:. Ak sa pridá nová trieda pre parameter, tak by sme museli modifikovať kvantum if-ov.Riešenie
Spočíva v postupnom znižovaní stupňa neurčitosti. V Smalltalk-u je totiž lepšie použiť polyformickú 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. Jednom veľmi peknou vlastnosťou Double Dispatching-u je, že kompletne nahradzuje podmienkové konštrukcie pre robustnejší kód. Pretože "hosť" prichádza k návšteve, návšteva vie, kde má spúšťať algoritmus pretože, už pozná typ hosťa. Toto odbúra množstvo rozhodnutí, ktoré by sme museli urobiť: Normálne sa musíme za za behu rozhodnúť (niekoľko-krát), kde a čo treba vykonať, ale tu už všetky rozhodnutia boli urobené na úrovni designu. Žiaden objekt sa nemusí pýtať žiadne otázky, robí to, čo má. 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 NumberTrieda Intereger a jej podtriedy používajú double dispatch na implementovanie niektorým základnýách aritmetických operácii. Práve tam je využite DD na mieste. Ukážeme si na operácii (metóde) #+ (plus).
#+ je definované Integerom takto
Integer>>+ aNumber
^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 spavil za nás.
ArithmeticValue>>addToInteger: anInteger
^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ť
addToInteger: anInteger
^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
- tie, čo posielajú správy argumentom
- tie, čo dedia, z nadtriedy argumentu
- a tie konečné metódy, ktoré urobia prácu
Výhody
- je oveľa viac objektovo orientovaný ako klasický prístup
- je rýchlejší: namiesto testovania "typu", pošle iba jednu alebo dve správy
- metódy sú o dosť menšie (viacmenej jednoriadkové), aj keď je ich trochu viac :)
- je to celé viac otvorené. Pri použití DD je jednoduchšie pridávať nové triedy. Nie je nutné meniť už existujúci kód, keď sa už rozhodnemem nejakú tú triedu pridať.
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äčší. Mnohé z operácií sú komutatívne(plus, prienik geometrických objektov), tak vieme počet metód redukovať. Existujú však na to aj iné techniky.Porovnanie
Z práce uvedenej v Linkoch a uplodnutej na toto Swiki uvádzam porovnanie počyu metód pred použitím DD, po použití (nedá sa nevšimnúť enormný nárast počtu metód) a po následnej redukcii DD metód podľa postupu uvedeného v práci Hebela & Johnsona. Porovnanie zahŕňa v podstate všetky "aritmetické" triedy (36 tried, 5 operátorov)
| x | predtým | DD bez redukcie | DD s redukciou |
| základné metódy | 180 | 180 | 180 |
| korekcie | 73 | 0 | 0 |
| Double Disptach | 0 | 6480 | 221 |
| Celkový počet | 253 | 6660 | 40 |
Linky
http://www.create.ucsb.edu/squeak/9703.html Squeak ST konferenciapráca Hebela & Johnsona o DD v ST 80
1-Sep-2011