Michal Valko: Double Dispatching

Double Dispatching

oop design pattern

Obsah

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 Number

Trieda 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
Jeden z dôvodov prečo možno vyzerá DD komplikovaný je, že nebol podporovaný v starom Smalltalku 80. Toto nútilo pogramátorov manuálne vytvárať všetky metódy vyžadované Double Dispatchingom. V súčasnosti už existujú nástroji na akési managovanie DD. DD metódy sa delia na 3 druhy
  1. tie, čo posielajú správy argumentom
  2. tie, čo dedia, z nadtriedy argumentu
  3. 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 konferencia
práca Hebela & Johnsona o DD v ST 80
1-Sep-2011