This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
laboratoare:tutorial-doubledispatch [2014/10/27 15:50] Daniel Ciocirlan |
laboratoare:tutorial-doubledispatch [2014/11/03 10:53] (current) Daniel Ciocirlan |
||
---|---|---|---|
Line 43: | Line 43: | ||
<code java> | <code java> | ||
boolean isPrime(int n) { | boolean isPrime(int n) { | ||
+ | // probably the dumbest way of testing a prime number | ||
+ | // not even complete (not that it may ever be) | ||
if (n == 2) | if (n == 2) | ||
return true; | return true; | ||
Line 59: | Line 61: | ||
===Double Dispatch=== | ===Double Dispatch=== | ||
- | Să ne uităm încă o dată la soluția precedentă. Observăm că obiectele ''A'' "acționează" asupra obiectelor ''B'', fără ca obiectele ''B'' să aibă nicio "implicare". Obiectele ''B'' sunt doar pasate ca parametri la metodele obiectelor ''A'' iar fiecare obiect ''A'' procesează, în mod polimorfic (**TODO link**), parametrul după implementarea proprie: | + | Să ne uităm încă o dată la soluția precedentă. Observăm că obiectele ''A'' "acționează" asupra obiectelor ''B'', fără ca obiectele ''B'' să aibă nicio "implicare". Obiectele ''B'' sunt doar pasate ca parametri la metodele obiectelor ''A'' iar fiecare obiect ''A'' procesează, în mod [[http://en.wikipedia.org/wiki/Polymorphism_(computer_science)#Subtyping|polimorfic]], parametrul după implementarea proprie: |
<code java> | <code java> | ||
Line 74: | Line 76: | ||
void accept(A a) { | void accept(A a) { | ||
a.interactWith(this); | a.interactWith(this); | ||
- | } | ||
- | |||
- | @Override | ||
- | public String toString() { | ||
- | return "B"; | ||
} | } | ||
} | } | ||
Line 85: | Line 82: | ||
void accept(A a) { | void accept(A a) { | ||
a.interactWith(this); | a.interactWith(this); | ||
- | } | ||
- | |||
- | public String toString() { | ||
- | return "B1"; | ||
} | } | ||
} | } | ||
Line 95: | Line 88: | ||
void accept(A a) { | void accept(A a) { | ||
a.interactWith(this); | a.interactWith(this); | ||
- | } | ||
- | |||
- | @Override | ||
- | public String toString() { | ||
- | return "B2"; | ||
} | } | ||
} | } | ||
Line 112: | Line 100: | ||
</code> | </code> | ||
- | **Întrebarea 1:** Ar avea, oare, același efect? De ce? Încercați! | + | **Întrebarea 1:** Ar avea, oare, același efect ca mai devreme? De ce? Încercați! |
Schimbarea mai mare intervine la clasele ''A''. Să spargem implementarea ''interactWith(B b)'', mutând codul din fiecare bloc ''instanceof'' în metode separate, ca în exemplul următor: | Schimbarea mai mare intervine la clasele ''A''. Să spargem implementarea ''interactWith(B b)'', mutând codul din fiecare bloc ''instanceof'' în metode separate, ca în exemplul următor: | ||
Line 139: | Line 127: | ||
Ne folosim, astfel, de tipurile concrete ale obiectelor care interacționează, **fără să testăm efectiv tipurile adevărate** în cod. Astfel, gândind în perspectivă, să răspundem la aceleași întrebări: | Ne folosim, astfel, de tipurile concrete ale obiectelor care interacționează, **fără să testăm efectiv tipurile adevărate** în cod. Astfel, gândind în perspectivă, să răspundem la aceleași întrebări: | ||
- | * Dacă adăugăm o nouă clasă în ierarhia ''A'', atunci ea trebuie să suprascrie toate metodele ''interactWith''. Oricum va trebui să implementeze operațiile diferite pentru fiecare ''B'' în parte, iar modularizarea este un plus. | + | * Dacă adăugăm o nouă clasă în ierarhia ''A'', atunci ea trebuie să suprascrie toate metodele ''interactWith''. Oricum va trebui să implementeze operațiile diferite pentru fiecare ''B'' în parte, iar **modularizarea este un plus**. |
- | * Dacă adăugăm o nouă clasă în ierarhia ''B'' (fie ea B3), trebuie să suprascrie metoda ''accept(A a)'', a cărei implementare va fi o singură linie: ''a.interactWith(this)'' => trebuie ca fiecare clasă ''A'' să aibă o nouă metodă ''interactWith(B3 b)''. | + | * Dacă adăugăm o nouă clasă în ierarhia ''B'' (fie ea ''B3''), trebuie să suprascrie metoda ''accept(A a)'', a cărei implementare va fi o singură linie: ''a.interactWith(this)'' => trebuie ca fiecare clasă ''A'' să aibă o nouă metodă ''interactWith(B3 b)''. |
- | * Cum arată codul pentru ierarhii mai mari? Structurat și organizat: | + | * Cum arată codul pentru ierarhii mai mari? **Structurat și organizat**: |
- | * fiecare clasă ''A'' are propriile implementări de interacțiuni, pe care, la nevoie, le putem modifica imediat, punctual | + | * fiecare clasă ''A'' are propriile implementări de interacțiuni, pe care, la nevoie, le putem modifica imediat, punctual, fără să căutăm în ''instanceof''-uri |
- | * nu mai facem absolut niciun test de tip concret pentru obiectele care interacționează; un mare beneficiu din punctul de vedere al extensibilității | + | * nu mai facem **absolut niciun test de tip concret** pentru obiectele care interacționează; un mare beneficiu din punctul de vedere al extensibilității |
+ | |||
+ | De ce se numește acest mecanism double dispatch? //Dispatch// este termenul folosit atunci când gândim ca mașina virtuală Java și ne referim la metoda //concretă// care se apelează la un moment dat. //Double// pentru că interacțiunea observăm că funcționează în ambele sensuri: ''B''-urile cheamă metoda proprie, concretă de ''accept'', care apelează metoda concretă ''interactWith'' din clasa ''A''. |