V tomto Φlßnku se seznßmφme s technikami objektovΘho designu, je₧ v opodstatn∞n²ch p°φpadech umo₧≥ujφ vyhnout se neÜikovnΘmu d∞d∞nφ a vytvß°enφ nov²ch t°φd: p∙jde o vyu₧φvßnφ delegßt∙ (a jim p°φbuznΘ techniky akce/cφl), o vyu₧itφ kategoriφ pro dopln∞nφ novΘho API ji₧ existujφcφ t°φd∞ a o vklßdßnφ objekt∙.
V °ad∞ objektov²ch prost°edφ je zvykem vyu₧φvat d∞diΦnost tak°ka na vÜe mo₧nΘ i nemo₧nΘ. Chceme omezit velikost okna nejv²Üe na 640 [215] 480 obrazov²ch bod∙? Dobrß, vytvo°φme si vlastnφ podt°φdu standardnφ systΘmovΘ t°φdy Window, v nφ₧ pat°iΦn²m zp∙sobem reimplementujeme metodu resize. Chceme tlaΦφtko, je₧ ukonΦφ aplikaci? Vytvo°φme vlastnφ podt°φdu standardnφ systΘmovΘ t°φdy Button, reimplementujeme v nφ metodu clicked tak, ₧e aplikaci ukonΦφ, a pro danΘ tlaΦφtko ji pou₧ijeme. Pot°ebujeme prioritnφ frontu objekt∙? Vytvo°φme podt°φdu standardnφ t°φdy Array a p°idßme pat°iΦnΘ slu₧by...
Ve skuteΦnosti vÜak takovΘ nadu₧φvßnφ d∞diΦnosti nenφ ideßlnφm objektov²m designem a v praxi p°inßÜφ °adu problΘm∙: nez°φdka vede k tomu, ₧e bychom pot°ebovali vφcenßsobnou d∞diΦnost (je₧ je v C++ problematickß a jinde nenφ v∙bec), Φasto takΘ zp∙sobuje kombinaci slu₧eb z logicky r∙zn²ch blok∙ aplikace v jedinΘm zdrojovΘm souboru. V d∙sledku pak omezuje reusabilitu a komplikuje dalÜφ ·pravy k≤du.
PODT╪═DY
ZaΦφt lze tφm, ₧e podt°φdy zcela b∞₧n∞ vytvß°φme. SouΦßstφ standardnφch knihoven Cocoa, kterou budeme pro ilustraci popisovan²ch technik pou₧φvat, je dokonce °ada t°φd, je₧ jsou p°φmo urΦeny k tomu, abychom v konkrΘtnφch aplikacφch pou₧φvali jejich konkrΘtnφ podt°φdy, a samy o sob∞ tΘm∞° nemajφ smysl (NSView). D∙le₧itΘ vÜak je, ₧e pro dosa₧enφ tΘho₧ cφle m∙₧eme vyu₧φt i jinΘ prost°edky, kterΘ jsou Φasto mnohem Üikovn∞jÜφ a znamenajφ menÜφ nßmahu pro programßtora (a menÜφ pravd∞podobnost chyb). Obecn∞ proto p°i objektovΘm designu platφ nßsledujφcφ pravidlo:
Pokud nepracujeme s t°φdou, je₧ je p°φmo navr₧ena pro d∞d∞nφ, m∞li bychom nejprve zvß₧it, zda pro vy°eÜenφ danΘho problΘmu nalezneme vhodnou cestu bez vytvß°enφ nov²ch t°φd. Teprve pokud tomu tak nenφ, m∞li bychom zaΦφt uva₧ovat o podt°φdßch - ne d°φve. Podφvejme se znovu na p°φklady z ·vodu:
* K omezenφ velikosti okna na 640 x 480 bod∙ je nejjednoduÜÜφ pou₧φt standardnφ okno a p°id∞lit mu tzv. delegßta - objekt, jeho₧ se okno "zeptß", mß-li zm∞nit velikost dan²m zp∙sobem.
* Pro tlaΦφtko ukonΦujφcφ aplikaci je nejjednoduÜÜφ pou₧φt standardnφ tlaΦφtko, definovat jeho akci jako zprßvu terminate: a p°id∞lit mu jako cφl objekt aplikace.
* Na prioritnφ frontu objekt∙ lze pou₧φt zcela obyΦejnou instanci t°φdy, reprezentujφcφ pole, a odpovφdajφcφ slu₧by doplnit prost°ednictvφm tzv. kategorie. (P°φpadn∞ m∙₧eme vytvo°it nov² objekt jako d∞dice zßkladnφ t°φdy a pole do n∞j vlo₧it. To je v²hodn∞jÜφ v p°φpad∞, ₧e po₧adujeme i dalÜφ atributy - dejme tomu, ₧e by naÜe prioritnφ fronta m∞la mφt jeÜt∞ jmΘno.)
DELEGACE
NejjednoduÜÜφ nßhradou pro °adu p°φpad∙ neÜikovnΘho d∞d∞nφ je delegace. Princip je prost². Mφsto toho, aby se t°φda sama o vÜechno starala prost°ednictvφm sv²ch vlastnφch metod, obsahuje instance t°φdy odkaz na spolupracujφcφ objekt, tzv. delegßta, s nφm₧ nejr∙zn∞jÜφ akce prost°ednictvφm odpovφdajφcφch zprßv "konzultuje".
Zßsadnφ v²hodou tohoto p°φstupu proti d∞d∞nφ je to, ₧e m∙₧eme funkΦn∞ odliÜnΘ bloky k≤du skuteΦn∞ rozd∞lit do r∙zn²ch t°φd. Objektov²m designem podle vzorce MVC (Model, View, Controller) se v rßmci tohoto Φlßnku podrobn∞ zab²vat nem∙₧eme; i bez v∞tÜφ teorie je vÜak z°ejmΘ, ₧e jde (nebo by aspo≥ m∞lo jφt) o pom∞rn∞ nezßvislΘ moduly. Zatφmco k≤d, kter² urΦuje, jak vypadß a jak funguje ovladaΦ pro zm∞nu velikosti, logicky pat°φ do objektu "okno", k≤d, kter² urΦuje, jak se okno m∙₧e zmenÜovat Φi zv∞tÜovat, pat°φ do ovladaΦe, kter² okno °φdφ, ale rozhodn∞ ne do okna samotnΘho (obr. 1).
Vyu₧itφ delegace takΘ obvykle i zjednoduÜφ k≤d aplikace: jen v²jimeΦn∞ toti₧ delegßta p°ipravujeme jako nov², samostatn² objekt. ╚ast∞ji jde o objekt, kter² slou₧φ zßrove≥ pro vφce logicky souvisejφcφch v∞cφ - nap°φklad m∙₧e jako delegßt °φdit okno pro zobrazenφ seznamu polo₧ek a zßrove≥ jako zdroj dat p°edßvat tyto polo₧ky tabulce, je₧ je uvnit° okna zobrazuje. Krom∞ toho se jeÜt∞ m∙₧e starat o aktivaci/deaktivaci tlaΦφtek, je₧ nad polo₧kami pracujφ.
Zßkladnφ mechanismus delegace je prost² a m∙₧eme jej ve vlastnφch t°φdßch s v²hodou vyu₧φvat. Instance mß prost∞ k dispozici prom∞nnou obsahujφcφ odkaz na delegßta, metody pro p°φstup k tΘto prom∞nnΘ, je₧ se standardn∞ jmenujφ delegate a setDelegate - a p°ed d∙le₧it²mi operacemi a/nebo po jejich provedenφ se delegßta zeptß (Φi jej informuje).
KonkrΘtnφ implementace zßvisφ na pou₧itΘm jazyce. V C++ je nutnΘ pro delegaci definovat abstraktnφ t°φdu, jejφmi₧ d∞dici budou vÜichni delegßti; to je samoz°ejm∞ neÜikovnΘ a nutφ nßs to vyu₧φvat vφcenßsobnΘ d∞diΦnosti, ale to je ji₧ dßno omezenφmi C++. V Jav∞ lze pro delegaci vyu₧φt interface, p°φpadn∞ (pro v∞tÜφ flexibilitu za cenu trochu slo₧it∞jÜφho k≤du) lze pou₧φt slu₧eb java.lang.reflect pro dosa₧enφ t²ch₧ mo₧nostφ, je₧ jsou v Objective C.
Standardnφ technikou v Objective C je vyu₧itφ tzv. neformßlnφho protokolu pro deklaraci zprßv, je₧ jsou delegßtovi posφlßny. Nejde o nic jinΘho ne₧ o rozhranφ kategorie pro t°φdu NSObject. Dφky n∞mu p°ekladaΦ zprßvy znß a vyhneme se "warning∙m" p°i jejich posφlßnφ:
// deklarace zprßv, posφlan²ch delegßtovi: @class OCJumper; @interface NSObject (OCJumperDelegate) -(BOOL)jumperShouldJump:(OCJumper*)jumper; // dotaz, zda mß b²t akce provedena @end // deklarace vlastnφ t°φdy: @interface OCJumper:... { id delegate;
Za zvlßÜtnφ zmφnku stojφ snad jen vyu₧itφ standardnφ metody respondsToSelector: (zd∞d∞nΘ od t°φdy NSObject) pro ov∞°enφ, zda delegßt zprßv∞ skuteΦn∞ rozumφ (na jejφm mφst∞ bychom v Jav∞ pou₧ili reflexi, v C++ nic podobnΘho nenφ). To je d∙le₧itΘ proto, abychom p°i implementaci delegßta mohli p°ipravit pouze metody, je₧ pot°ebujeme, a nemuseli se zdr₧ovat implementacφ ostatnφch:
@implementation OCJumper -delegate { return delegate; } -(void)setDelegate:del { delegate=del; } ... -(void)performJump { // vlastnφ akce: nenφ v rozhranφ, jde o privßtnφ metodu ... } -(void)jump {
// pokud delegßt rozumφ zprßv∞ jumperShouldJump: a odpovφ NO... if ([delegate respondsToSelector:@selector(jumperShouldJump:)] &&
![delegate jumperShouldJump:self]) return; // ... ned∞lßme nic [self performJump]; // jinak provedeme vlastnφ akci } ... @end
MECHANISMUS AKCE/C═L
Mechanismus akce/cφl (action/target) je urΦitou alternativou delegace. Podobn∞ jako objekt m∙₧e udr₧ovat odkaz na delegßta, m∙₧e takΘ udr₧ovat odkaz na cφl (target), objekt, kter² bude informovßn o provedenφ n∞jakΘ zßsadnφ operace. JednoznaΦnΘ to b²vß u objekt∙ GUI - takto zßsadnφ operacφ pro tlaΦφtko je jeho stisknutφ, pro nabφdku v²b∞r n∞kterΘ z jejφch polo₧ek, pro textovΘ pole ukonΦenφ jeho editace apod.
Mechanismus akce/cφl je proti delegaci flexibiln∞jÜφ v tom, ₧e i zprßva zasφlanß objektem je prom∞nnß, nenφ tedy pevn∞ urΦena, jako zprßva delegßta. Mφsto toho instance obsahuje vhodnou prom∞nnou - v Jav∞ String obsahujφcφ jmΘno metody (odeslanΘ pomocφ reflexe), v Objective C vyu₧ijeme typu SEL a standardnφ metody zd∞d∞nΘ od t°φdy NSObject pro odeslßnφ zprßvy - velmi p°ibli₧n∞ takto:
// Akce/cφl pro tlaΦφtko [8212] princip @interface Button:... {
V²hody proti vyu₧itφ d∞diΦnosti jsou obrovskΘ. Nejen₧e nemusφme "mφchat" k≤d pro °φzenφ aplikace s k≤dem samotnΘho tlaΦφtka, nemusφme ani psßt nic "navφc". Pokud je po₧adovanß slu₧ba ji₧ n∞kde k dispozici, prost∞ vezmeme tlaΦφtko a jen vhodn∞ nastavφme jeho target a action.
KATEGORIE
Pokud chceme sestavit jen specifickΘ API, je₧ nepo₧aduje zßsadnφ rozÜφ°enφ slu₧eb, lze vzφt ji₧ hotovou t°φdu a slu₧by doplnit prost°ednictvφm tzv. kategorie. To se "klasickΘmu" vytvß°enφ podt°φdy hodn∞ podobß; z hlediska programßtora je vlastn∞ jedin² rozdφl v tom, ₧e nenφ t°eba vytvß°et novou t°φdu. NovΘ metody vÜak implementuje p°esn∞ stejn²m zp∙sobem, jako by tomu bylo p°i vyu₧itφ d∞diΦnosti. Podφvejme se na obr. 2 a 3; ty dob°e ilustrujφ jak podobnost, tak i rozdφly obou p°φstup∙.
Uka₧me si nejjednoduÜÜφ p°φklad implementace zßsobnφku. Jednou ze standardnφch t°φd, je₧ knihovny Cocoa nabφzejφ, je dynamickΘ pole objekt∙, NSMutableArray. Je celkem z°ejmΘ, ₧e nejjednoduÜÜφ bude implementovat zßsobnφk prßv∞ dopln∞nφm slu₧eb k tΘto t°φd∞ - v rozhranφ prost∞ jen deklarujeme novΘ zprßvy:
[self addObject:object]; } -pop { id o=[[[self lastObject] retain] autorelease];
[self removeLastObject]; return o; } @end
Metody addObject:, lastObject a removeLastObject jsou standardnφmi metodami t°φdy NSMutableArray a jejich funkce je z°ejmß z jejich jmen. Metody retain, autorelease a jejich vyu₧itφ jsou danΘ zp∙sobem, jφm₧ Cocoa °φdφ sprßvu pam∞ti, a jejich vysv∞tlenφ by p°esßhlo rozsah Φlßnku.
JakΘ jsou v²hody a nev²hody tohoto vyu₧itφ kategorie?
+ Kategorie funguje stejn∞ dob°e s obyΦejnou t°φdou i se sdru₧en²mi t°φdami (class clusters) - s nimi by se obyΦejnß d∞diΦnost nedala p°φmo vyu₧φt.
+ Objekty typu zßsobnφk jsou oboustrann∞ stoprocentn∞ kompatibilnφ s instancemi NSMutableArray (jde prakticky o objekty tΘ₧e t°φdy). N∞jak² modul tedy m∙₧e vytvo°it pole NSMutableArray a jin² m∙₧e s t²m₧ objektem pracovat jako se zßsobnφkem. To by nebylo mo₧nΘ u objekt∙ r∙zn²ch t°φd (platila by kompatibilita jen jednφm sm∞rem).
Mßme-li nap°φklad slu₧by pro archivaci objekt∙ do formßtu XML, je₧ podporujφ pole, m∙₧eme je beze zm∞ny vyu₧φt i pro nßÜ zßsobnφk. Pokud bychom pro zßsobnφk m∞li samostatnou t°φdu, bylo by nutnΘ pou₧it² formßt XML rozÜφ°it tak, aby tuto t°φdu explicitn∞ podporoval. Podobn∞ je tomu i p°i sdφlenφ objekt∙ mezi r∙zn²mi procesy a podobn∞.
- Obecnou nev²hodou kategorie je, ₧e nenφ mo₧nΘ p°φmo p°idßvat instanΦnφ prom∞nnΘ. Pokud bychom to pot°ebovali, existujφ sice triky, jak to zaonaΦit, avÜak obvykle u₧ je lepÜφ vyu₧φt spφÜe vklßdßnφ objekt∙ (nebo "klasickou" d∞diΦnost, pokud nenarazφme na sdru₧enΘ t°φdy Φi na jin² problΘm).
- P°i vyu₧itφ kategorie tφmto zp∙sobem takΘ nelze zm∞nit standardnφ chovßnφ zßkladnφ t°φdy (to musφ z∙stat k dispozici pro moduly, je₧ t°φdu vyu₧φvajφ b∞₧n²m zp∙sobem). Pokud tedy po₧adovanΘ chovßnφ novΘho objektu nenφ pouh²m rozÜφ°enφm slu₧eb objektu p∙vodnφho, nelze kategorii pou₧φt.
Tam, kde je n∞kterß z t∞chto nev²hod kritickß, mßme k dispozici vklßdßnφ objekt∙.
VKL┴D┴N═ OBJEKT┘ A P╪ESM╠ROV┴N═ ZPR┴V
Pro lepÜφ pochopenφ toho, jak vklßdßnφ objekt∙ funguje, je vhodnΘ se podφvat na obr. 2 a uv∞domit si, co se d∞je, kdy₧ objektu Zßsobnφk poÜleme n∞jakou zprßvu:
* Pokud je odpovφdajφcφ metoda souΦßstφ t°φdy Zßsobnφk (je ve skupin∞ novΘ slu₧by), prost∞ se provede.
* Pokud tomu tak nenφ, hledß se odpovφdajφcφ metoda ve t°φd∞ Pole.
Vklßdßnφ objekt∙ dosahuje tΘho₧ efektu trochu jinak: t°φda Zßsobnφk nenφ d∞dicem t°φdy Pole, ale obsahuje vlo₧en² objekt t°φdy Pole. T°φda je implementovßna tak, aby se zprßvy, jim₧ sama "nerozumφ", p°esm∞rovaly na tento vno°en² objekt (obr. 4). Implicitnφ d∞diΦnost tedy nahrazuje explicitnφ p°edßvßnφ zprßv.
Vklßdßnφ objekt∙ je slo₧it∞jÜφ ne₧ prostΘ vyu₧itφ d∞diΦnosti. Krom∞ nov²ch slu₧eb musφme navφc explicitn∞ implementovat p°edßvßnφ zprßv. V²m∞nou za to ovÜem zφskßme znaΦnou flexibilitu:
* Vlo₧en² objekt nemusφ b²t vytvo°en hned p°i tvorb∞ hlavnφho objektu, lze jej vytvo°it, a₧ kdy₧ je poprvΘ zapot°ebφ. V n∞kter²ch p°φpadech to m∙₧e znamenat skuteΦn∞ zßsadnφ rozdφl - pokud se vytvß°φ mnoho instancφ zßkladnφch objekt∙, vlo₧enΘ objekty jsou velkΘ a pou₧φvajφ se z°φdka, m∙₧e tato technika mnohonßsobn∞ snφ₧it spot°ebu pam∞ti a zrychlit aplikaci.
* Vlo₧en² objekt nemusφ b²t po celou dobu existence zßkladnφho objektu tent²₧. Podle pot°eby m∙₧e zßkladnφ objekt kdykoli nahradit objekt vlo₧en² jinou instancφ, dokonce i instancφ jinΘ t°φdy. Vlo₧en²ch objekt∙ m∙₧e b²t i vφce a zßkladnφ objekt se m∙₧e dynamicky rozhodnout, kterΘmu z nich zprßvu p°edß. Tak m∙₧eme efektivn∞ implementovat de facto vφcenßsobnou d∞diΦnost, ani₧ bychom narazili na nev²hody, je₧ jsou s nφ spjaty v jazycφch typu C++, je₧ ji nabφzejφ p°φmo.
* Proto₧e p°edßvßnφ zprßv mezi zßkladnφm a vlo₧en²m objektem je "jejich internφ v∞c", skrytß v rßmci zapouzd°enφ uvnit° API zßkladnφho objektu a neovliv≥ujφcφ zbytek aplikace, m∙₧eme pro n∞j pou₧φt r∙znΘ nestandardnφ metody. Typick²m vyu₧itφm tΘto mo₧nosti jsou tzv. distribuovanΘ objekty - odkaz na objekt obsahuje identifikaci poΦφtaΦe a procesu a p°edßvßnφ zprßv je zajiÜt∞no prost°ednictvφm meziprocesovΘ komunikace a/nebo poΦφtaΦovΘ sφt∞. Tak m∙₧eme transparentn∞ "p°φmo" pracovat s objekty, je₧ jsou fakticky souΦßstφ jinΘho procesu na jinΘm poΦφtaΦi.
DalÜφ v²hodou vklßdßnφ objekt∙ je i to, ₧e bez problΘm∙ funguje i se sdru₧en²mi t°φdami - "klasickß" d∞diΦnost je u t∞chto specißlnφch t°φd problematickß, resp. slou₧φ u nich pro zcela jin² ·Φel.
ROZHRAN═
Pro ilustraci si ukß₧eme implementaci jednoduchΘho zßsobnφku pomocφ vklßdßnφ objekt∙, i kdy₧ zde by se kategorie hodila lΘpe. Rozhranφ je pom∞rn∞ jednoduchΘ - krom∞ deklarace API pot°ebujeme jen jednu instanΦnφ prom∞nnou, je₧ bude obsahovat odkaz na vlo₧en² objekt:
V praxi bychom asi vklßdßnφ objekt∙ vyu₧ili ve slo₧it∞jÜφch p°φpadech, kdy by instanΦnφch prom∞nn²ch bylo vφce.
IMPLEMENTACE
Implementace je tentokrßt trochu slo₧it∞jÜφ, a proto si ji ukß₧eme v n∞kolika krocφch. Nejprve to nejjednoduÜÜφ: zßsobnφkovß primitiva p°evedeme na primitiva dynamickΘho pole prakticky stejn∞, jako tomu bylo u kategorie, jen mφsto odkazu self sßm na sebe pou₧ijeme odkaz na vlo₧en² objekt:
@implementation Stack -(void)push:object {
[array addObject:object]; } -pop { id o=[[[array lastObject] retain] autorelease];
[array removeLastObject]; return o; }
Celkem jednoduchß je i standardnφ implementace "konstruktoru" init, v n∞m₧ vytvo°φme vlo₧en² objekt:
Pokud po₧adujeme jen novΘ API (reprezentovanΘ zprßvami push: a pop), jsme hotovi. Sice jsme museli napsat nepatrn∞ vφce k≤du ne₧ p°i pou₧itφ kategorie podt°φdy, zato se nßm vÜak neplete dohromady starΘ a novΘ API a pou₧itß technika funguje stejn∞ dob°e se sdru₧en²mi i s normßlnφmi t°φdami. Navφc mßme v²hodu mo₧nosti inicializovat vlo₧en² objekt dynamicky a₧ v p°φpad∞ pot°eby - prost∞ bychom zruÜili implementaci metody init a na zaΦßtek metod push: a pop bychom p°idali °ßdek if (!array) array=[[NSMutableArray alloc] init];
V obecnΘm p°φpad∞ vÜak to, ₧e se nßm neplete starΘ a novΘ API, p°inßÜφ vlastnφ problΘmy, nebo¥ to znamenß, ₧e nad objekty t°φdy Stack nem∙₧eme u₧φvat slu₧eb t°φdy NSMutableArray. To proto, ₧e jsme dosud neimplementovali vlastnφ p°esm∞rovßnφ zprßv - a₧ dosud jsme vyu₧φvali jen vklßdßnφ objekt∙; hned to napravφme.
P╪ESM╠ROV┴N═ ZPR┴V
Pro p°esm∞rovßnφ zprßv musφme mφt k dispozici odpovφdajφcφ slu₧bu runtime: jde o algoritmus p°edßvßnφ zprßvy objektu, kter² musφ obsahovat pln∞ dynamickß "zadnφ vrßtka" pro p°φpad, ₧e se nenajde odpovφdajφcφ metoda. V Objective C s knihovnami Cocoa je mo₧nost p°esm∞rovßnφ standardn∞. Lze ji zajistit i v Jav∞ s nestandardnφmi knihovnami (standardnφ Java ji ani s vyu₧itφm reflexe nenabφzφ). Pokud se v ₧ßdnΘ nadt°φd∞ nenajde odpovφdajφcφ metoda, runtime systΘm se pokusφ odeslat zprßvu dynamicky, nezßvisle na metodßch, je₧ jsou souΦßstφ t°φd. TakovΘ dynamickΘ odeslßnφ zprßvy pak probφhß ve dvou krocφch:
* Nejprve se runtime systΘm objektu "zeptß", jakΘ jsou typy argument∙ a nßvratovß hodnota odpovφdajφcφ danΘ zprßv∞.
* Pak runtime systΘm vytvo°φ "balφΦek" reprezentujφcφ zprßvu i jejφ argumenty (aby to bylo korektn∞ mo₧nΘ s libovoln²mi typy, musel nejprve prob∞hnout prvnφ krok) a ten objektu p°edß. Objekt s nφm m∙₧e ud∞lat cokoliv, v naÜem p°φpad∞ jej p°edß vlo₧enΘmu objektu, aby jej zpracoval za n∞j.
Oba kroky jsou realizovßny pomocφ standardizovan²ch zprßv. Pro prvnφ z nich slou₧φ zprßva methodSignatureForSelector:, jejφm₧ argumentem je tzv. selektor (v podstat∞ zak≤dovanΘ jmΘno) danΘ zprßvy. Vrßcenß hodnota je specißlnφ objekt t°φdy NSMethodSignature, kter² podrobn∞ urΦuje vÜechny atributy metody, tj. poΦet a typy jejφch argument∙ i typ jejφ nßvratovΘ hodnoty. Pro druh² krok je urΦena zprßva forwardInvocation:, jejφm₧ argumentem je specißlnφ objekt t°φdy NSInvocation. Ten slou₧φ jako v²Üe zmφn∞n² "balφΦek" - jeho souΦßstφ jsou konkrΘtnφ hodnoty argument∙ i selektor zprßvy a jeho prost°ednictvφm se p°edßvß i nßvratovß hodnota.
Znφ to mo₧nß slo₧it∞, ale konkrΘtnφ implementace p°esm∞rovßnφ vÜech neznßm²ch zprßv na vlo₧en² objekt je velmi jednoduchß:
V prvnφ metod∞ si vy₧ßdßme signaturu od vlo₧enΘho objektu. V implementaci druhΘ metody forwardInvocation: jen p°edßme objektu inv po₧adavek, aby zprßva, ji₧ reprezentuje, byla zaslßna objektu array - to zajistφ standardnφ metoda invokeWithTarget:, je₧ je souΦßstφ knihovnφ implementace t°φdy NSInvocation.
V▌HODY A NEV▌HODY
O n∞kter²ch v²hodßch vklßdßnφ objekt∙ a p°esm∞rovßnφ zprßv jsme u₧ hovo°ili, je jich vÜak vφce:
+ Vklßdßnφ objekt∙ a p°esm∞rovßnφ zprßv korektn∞ podporuje sdru₧enΘ i normßlnφ t°φdy.
+ Vlo₧en² objekt nemusφ b²t vytvo°en hned p°i tvorb∞ hlavnφho objektu, lze jej vytvo°it "on-demand" a₧ ve chvφli, kdy je poprvΘ zapot°ebφ.
+ Vlo₧en² objekt nemusφ b²t po celou dobu existence zßkladnφho objektu t²₧. Podle pot°eby m∙₧e zßkladnφ objekt kdykoli nahradit vlo₧en² objekt jinou instancφ, v komplexn∞jÜφch p°φpadech i instancφ jinΘ t°φdy. Podobn∞ m∙₧e b²t vlo₧en²ch objekt∙ vφce a zßkladnφ objekt se m∙₧e podle podmφnek a pot°eby dynamicky rozhodnout, kterΘmu zprßvu p°edß.
+ Proto₧e p°edßvßnφ zprßv mezi zßkladnφm a vlo₧en²m objektem je "jejich internφ v∞cφ", skrytou v rßmci zapouzd°enφ uvnit° API zßkladnφho objektu a neovliv≥ujφcφ zbytek aplikace, m∙₧eme pro n∞j pou₧φt r∙znΘ nestandardnφ metody.
+ P°i vklßdßnφ objekt∙ a p°esm∞rovßnφ zprßv lze snadno skr²t API, je₧ nechceme publikovat (jako by z∙stalo skryto kompletnφ API t°φdy NSMutableArray, kdybychom p°esm∞rovßnφ zprßv neimplementovali). Stejn∞ dob°e m∙₧eme p°i p°esm∞rovßvßnφ dynamicky volit, kterΘ zprßvy p°edßme, a kterΘ ne.
- Proti vyu₧itφ kategorie ztrßcφme v²hodu oboustrannΘ kompatibility (dostaneme-li instanci t°φdy NSMutableArray, nem∙₧eme ji p°φmo vyu₧φvat jako zßsobnφk).
Proti d∞diΦnosti nemß p°esm∞rovßnφ tak°ka ₧ßdnou nev²hodu, nepoΦφtßme-li t∞ch cca osm °ßdk∙ zdrojovΘho k≤du, je₧ musφme napsat navφc pro implementaci vlastnφho p°esm∞rovßnφ.
SHRNUT═
P°esto₧e d∞diΦnost je a z∙stane zßkladnφ a nesmφrn∞ cennou vlastnostφ objektov²ch systΘm∙, je t°eba dßt si pozor na jejφ nadu₧φvßnφ, je₧ n∞kdy vede ke zbyteΦn∞ komplikovanΘmu k≤du a jindy k nevhodnΘmu designu (jmenovit∞ k "pror∙stßnφ" modul∙, je₧ by m∞ly v rßmci modelu MVC z∙stat samostatn²mi). P°itom existuje °ada technik, kterΘ dokß₧φ d∞diΦnost efektivn∞ a s n∞kter²mi v²hodami nahradit - od jednoduchΘ delegace, p°φstupnΘ prakticky v libovolnΘm prost°edφ, a₧ po nejflexibiln∞jÜφ vklßdßnφ objekt∙ a p°esm∞rovßnφ, je₧ ovÜem vy₧aduje dynamick² objektov² jazyk s vhodn²m runtime. M∙₧eme tedy odpov∞d∞t na otßzku z nadpisu: Podt°φdy, delegßti, vklßdßnφ - jak se to r²muje? Inu, t°eba takto: Na podt°φdy bacha, delegßt, ten fachß, vklßdßnφ je °acha, tak se to r²muje.