VZOR HETEROGENNÍ SEZNAM S KONFIGURACÍ POVOLENÝCH KOMBINACÍ DĚDICŮ RNDr. Ilja Kraval, září 2008 http://www.objects.cz ÚVOD Jak známo, v CLASS DIAGRAMU se dělí vztahy do dvou základních typů: Buď se jedná o asociaci anebo o generalizaci. Zatímco asociace vede ve svém důsledku v instanční rovině ke vztahu mezi instancemi, generalizace vyjadřuje interakci použití pouze mezi třídami, tj. jedná se o použití mezi typy, které se neprojeví jako vztah mezi instancemi. Záměna těchto dvou typů interakce patří k velmi hrubým chybám při návrhu IS a bohužel tyto chyby jsou velmi časté. Z toho důvodu se vysvětlení obou vztahů a jejich rozdílu věnuje velká pozornost v našich školeních Pobytový kurz OOP a UML anebo distanční e-kurz Kurz profesního růstu analytika od základů. Dá se říci, že znalost fungování těchto dvou vztahů patří opravdu k elementární gramotnosti při návrhu IS. Syntaxe CLASS DIAGRAMU je samozřejmě platná pro všechny úrovně abstrakce včetně analytického modelování. V této fázi existuje naštěstí několik málo základních situací, tj. analytických vzorů, které vedou k použití generalizace. Je opravdu dobré všechny tyto situace znát. Jedním z takových často opakujících se řešení je vzor HETEROGENNÍ SEZNAM. VZOR HETEROGENNÍ SEZNAM Jedná se o velmi častý případ, kdy přistupujeme k seznamu z prvků a přitom v daném seznamu se vyskytují prvky různých typů. Je třeba zdůraznit, že daný seznam prvků chápeme jako jeden seznam a nikoliv jako dva seznamy nebo více seznamů typově odlišných prvků. Abychom mohli takovýto typově heterogenní seznam zavést, musíme zavést společného předka generalizace, neboli laicky řečeno, obecnější pojem. Hovoříme totiž o seznamu daného pojmu na vyšší úrovni generalizace, ale máme přitom na mysli instance seznamu z konkrétních podtypů.
strana 2 Paradoxně laik tuto na první pohled složitou situaci chápe velmi dobře, jenom ji neumí vyjádřit pomocí syntaxe UML. Popisuje ji pomocí vlastních slov při použití zdravého selského rozumu. Představme si následující příklad: V realitě, například u domu na dvorku, vidíme několik psů a několik koček, jak se prohánějí. Znamená to, že některé prvky na dvoře jsou typu Pes a některé prvky na dvoře jsou typu Kočka. Pokud bychom chtěli tuto situaci vyjádřit pomocí CLASS DIAGRAMU, tj. zobecnit situaci na dvoře do jakéhosi obecného pravidla, tj. zobecnit situaci do tzv. meta pravidla všech budoucích instancí dvorků, potom se nabízejí dvě možná řešení: 1. Pro skupinu psů zavedeme seznam psů na dvorku a pro skupinu koček zavedeme seznam koček na dvorku. Všimněme si, že jsme na dvorku zavedli dva seznamy, jeden pro psy a jeden pro kočky. Pokud chceme obsloužit nějakým příkazem jak psy, tak kočky, musíme obsloužit dva vedle sebe stojící seznamy, tj. pracovat se psy zvlášť a s kočkami zvlášť. 2. Druhou možností je využít generalizace. Zavedeme obecnější pojem v generalizaci (tj. obecnější třídu v generalizaci), nazvěme ji Zvíře, a zavedeme její podtypy v generalizaci jako typ Pes a typ Kočka. Díky kompatibilitě zespodu nahoru, což je základní vlastnost generalizace (podrobně viz uvedená školení), se kdekoliv na konci asociace tam, kde je uvedena třída Zvíře, může v dané roli vyskytovat instance potomka, tedy instance buď typu Pes anebo instance typu Kočka. V tomto řešení díky tomu zavádíme pouze jeden seznam a to seznam zvířat, který je definován jako seznam s asociací prvku typu Dvůr na typ Zvíře, ale konkrétně se v seznamu vyskytují prvky neboli instance více speciálních podtypů Pes nebo Kočka. Znamená to, že na rozdíl od předešlého případu dvorek, drží jeden seznam, a to seznam zvířat a v něm se vyskytují jak psi, tak kočky. První řešení bez generalizace bychom mohli znázornit v UML takto: strana 2
strana 3 Pes Dv ur Kočka Obrázek 1 Řešení bez generalizace Druhé řešení by mohlo být znázorněno pomocí UML takto: Dv ur Zvíře Pes Kočka Obrázek 2 Generalizace v kombinaci s agregací, heterogenní seznam Rozdíl mezi oběma řešeními 1 a 2 na předešlých obrázcích se nezdá až tak velký, protože v instancích jsou si velmi podobné. Instančně se dokonce mohou jevit až jako shodné: Představme instanci dvora (konkrétní dvůr), označme jej jako Dvur1 a na něm jsou tři kočky K1, K2, K3 a dva psi P1, P2. Namalujme linky mezi prvky takto: strana 3
strana 4 K1 Dv ur1 K2 P1 K3 P2 Obrázek 3 Instanční model psů a koček na dvorku Když se podíváme na předešlý obrázek, existují dva možné pohledy na linky (spojnice mezi instancemi): 1. Linky jako spojnice mezi instancí Dvur1 na jedné straně a K1, K2, K3 na straně druhé patří do jednoho seznamu a současně všechna spojení mezi Dvur1 a P1, P2 patří do druhého seznamu. Zvolili jsme tímto řešení bez generalizace se dvěma asociacemi, tj. máme dva seznamy, jeden pro psy, druhý pro kočky. Tomu odpovídá Obrázek 1. 2. Úplně všechny linky na obrázku, tj. na jedné straně spojnice Dvur1 a na straně druhé K1, K2, K3, P1, P2 spadají pod jeden vztah asociace a jsou všechny jeho realizací (tj. realizovány jeho instanciováním). Protože prvky K1, K2, a K3 patří do jedné třídy Kočka a P1, P2 do druhé třídy Pes, musí být tento společný vztah realizován přes předka, nazvěme tuto třídu Zvíře. Zvolili jsme tímto řešení s generalizací a s jednou asociací, tj. máme jeden seznam zvířat a v něm figurují jak kočky, tak psi. V tomto případě tomuto řešení odpovídá Obrázek 2. Rozdíl mezi oběma řešeními je důležitý hlavně ze dvou hledisek: Za prvé z pohledu analytické přehlednosti a za druhé z hlediska typové flexibility. 1. ANALYTICKÁ PŘEHLEDNOST. U druhého řešení s generalizací i laik hovoří o seznamu zvířat a rozumí mu. Například jsou srozumitelné a jasné věty typu vyhnali strana 4
strana 5 jsme všechna zvířata ze dvorku, sečteme počet zvířat ve dvorku, všechna zvířata ve dvorku vydávají jako reakci na podnět zvuk, ale každý podle svého typu (pozn.: Všimněme si, že se jedná o laickou, ale přesně vyjádřenou vlastnost polymorfního chování), to vše je laikovi jasné. Stejně jednoduše to funguje i v UML, jedná se jen o grafický zápis těchto vět a úvah nad nimi. 2. TYPOVÁ FLEXIBILITA. Pokud u řešení s generalizací přidáme nový druh zvířete jako nový podtyp zvířete (například typ Kachna jako další dědic typu Zvíře ), tak do předešlých vět předešlého odstavce nemusíme vůbec zasahovat. Ten, kdo obsluhuje seznam zvířat, se nestará o podtypy typu Zvíře. Pokud bychom však použili první řešení bez generalizace (viz Obrázek 1), tj. pro každý typ zvířete bychom zavedli pokaždé nový seznam zvlášť, museli bychom přidat nový seznam v dvorku k již hotovým seznamům a překopat tak strukturu dvorku. Uvedené řešení našeho dvorku s generalizací pomocí pojmu Zvíře zobecníme do vzoru HETEROGENNÍ SEZNAM. V mnoha případech se i v evidenci setkáváme s podobným problémem. Všude tam, kde hovoříme o seznamu z obecnějších pojmů (zde seznam zvířat), ale přitom máme na mysli prvky z konkrétních podtypů (zde konkrétní kočky a konkrétní psi), tam se hodí použít vzor HETEROGENNÍ SEZNAM, jehož strukturu bychom mohli vyjádřit takto: X A A1 A2 An... Obrázek 4 Obecný vzor heterogenní seznam Popis vzoru: Nějaký obecný prvek X drží seznam z A, což mohou být A1, A2,...až An. strana 5
strana 6 Možné varianty vzoru HETEROGENNÍ SEZNAM: 1. Agregací může být buď kompozice anebo sdílená agregace. 2. Třída A bývá většinou abstraktní. Uveďme příklady použití: Hovoříme o seznamu přijatých zpráv různého typu, o zpracování dokladů různého typu, o seznamu bankovních služeb různého typu atd. Uvedený vzor ještě není předmětem tohoto článku, je probrán jako základní látka uvedených dvou školení (školení viz Pobytový kurz OOP a UML a distanční e-kurz Kurz profesního růstu analytika od základů ). ZADÁNÍ PROBLÉMU POVOLENÝCH KOMBINACÍ V HETEROGENNÍM SEZNAMU V jedné firmě při školení OOP a UML se právě při probírání vzoru HETEROGENNÍ SEZNAM vynořil zajímavý problém k řešení. Protože školení má i konzultační charakter, také jsme jej hned u tabule vyřešili. Jak zadání problému, tak i řešení mne natolik zaujalo, že jej předkládám v tomto článku. Otázka problému k řešení zněla: Co kdybychom potřebovali instančně omezit resp. naopak instančně povolit některé kombinace možných zrodů instancí z podtypů daného použití vzoru? Zní to sice složitě, a proto si vše vysvětlíme na příkladu s našimi zvířaty: Existovaly by různé druhy dvorků podle povolených kombinací, jak se mohou rodit instance z potomků (tj. různé kombinace omezení počtů koček a psů). Například v prvním druhu dvorku by byla povolena pouze existence kombinace právě jeden pes a právě jedna kočka a nic víc. V druhém druhu dvorku by bylo povoleno jeden pes a koček kolik chceš. V dalším druhu dvorku by byla povolena kombinace kolik psů chceš, ale jen právě dvě kočky atd. Tyto kombinace by si zadávala obsluha a zakládala by tak povolené možné druhy dvorků. Takovýto požadavek může vzniknout v evidenci IS: Například určitému klientovi daného typu můžeme dát úvěr jenom jednou, ale ostatní služby má bez omezení apod., ale jiný klient jiného typu může mít úvěrů kolik chce. Nebo jiný příklad: Určitý druh zprávy může mít pouze jednu informaci typu 1, ale N informací typu 2. Jiný druh zprávy může mít N informací typu 1 a právě dvě informace typu 2 atd. Všimněme si nejprve, že na úrovni tříd jsou všechny uvedené kombinace v modelu Obrázek 2 povoleny, ale nikoliv omezeny. Znamená to, že model tříd Obrázek 2 povoluje všechny vyslovené kombinace v předešlém odstavci, ale současně nevymezuje, že za daných okolností musí nastat právě jedna z nich. Například z modelu Obrázek 2 plyne, že můžeme instančně vytvořit seznam o dvou zvířatech, první bude pes a druhé bude kočka. Tím jsme vytvořili jednu ze zmíněných kombinací jeden pes a jedna kočka, ale zadání zní jinak: Potřebujeme omezit, že pokud zvolíme druh dvorku s omezením jeden pes a jedna kočka, strana 6
strana 7 nedovolí se u tohoto dvorku založit jiná kombinace, než jeden pes a jedna kočka. Model Obrázek 2 však nyní dovoluje založit libovolnou kombinaci ze všech podtypů. Model na zmíněném obrázku má vlastně jakoby implicitně přiřazenu kombinaci kolik koček chceš a kolik psů chceš a to bez omezení. Instančně si tedy zadání problému můžeme představit takto: Máme dán model tříd zvířat na dvorku, viz Obrázek 2. Jsou zadány povolené kombinace zrodu instancí, například takto: Kombinace 1 = (pes 1, koček ) Kombinace 2 = (pes, koček 2) atd. Přiřadíme jednu z těchto kombinací jako vlastnost danému dvorku při jeho zrodu, tj. řekneme při zrodu dvorku: Jsi tohoto druhu povolené kombinace a on bude rodit v seznamu zvířat kočky a psy omezeně podle této kombinace. Jinému dvorku dáme do vínku jinou kombinaci a máme dvorek s jinou povolenou kombinací. Potom budou nastávat požadované situace, kdy jeden konkrétní dvorek může mít pouze jednoho psa a jednu kočku, jiný konkrétní dvorek může mít N psů a právě dvě kočky atd. (viz předešlé kombinace). Jak navrhnout model tříd, který toto bude podporovat? Zatím v modelu toto řešení nemáme K řešení musíme znát ještě jeden analytický vzor, který je také součástí výkladu obou školení (viz Pobytový kurz OOP a UML a distanční e-kurz Kurz profesního růstu analytika od základů ). Tento vzor se nazývá DISKRIMINÁTOR. O něm a o řešení příkladu bude pojednáno příště Pokračování příště strana 7