nový analytický vzor
"Asociační třída na vrcholu stromu”
a jeho rozbor

 

 

3. část

 

autor: RNDr. Ilja Kraval, leden 2011

 

Object Consulting s.r.o.

 

Server objektových technologií

 

http://www.objects.cz

 

 

 

 

 

 

 

 

Úvod

 

V minulých článcích jsme si představili nový vzor nazvaný „Asociační třída na vrcholu stromu“. Jedná se o kombinaci dvou vztahů v modelu tříd: Asociační třídy a generalizace. V minulém článku jsme model tohoto vzoru doplnili o tzv. diskriminátor (Vzor Diskriminátor viz kniha Analytické modelování pomocí UML v praxi, strana 77). Dále jsme uvedený vzor vylepšili o vyšší odolnost vůči chybám (lidově řečeno o tak zvanou „blbovzdornost“) pomocí vzoru Povolené kombinace, který jsme nasadili na možné typy vztahů.

 

V tomto článku si ukážeme nejčastější použití vzoru „Asociační třída na vrcholu stromu“ a také možná úskalí při využití tohoto vzoru.  

 

 

Nejčastější možná použití vzoru

 

Agenda subjektů alias Party

 

Minule jsme si uvedli první známé použití vzoru „Asociační třída na vrcholu stromu“ u agendy Subjektů (Party). Toto nasazení vzoru nebudu již dále podrobně popisovat, zájemce odkazuji například na knihu Analytické modelování pomocí UML v praxi, kde je vzor Party podrobně popsán.

 

Vztahy mezi doklady a vztahy mezi řádky dokladu

 

Druhé možné použití je nasadit vzor „Asociační třída na vrcholu stromu“ na vztah mezi doklady a na vztah mezi řádky dokladu. Nejprve zavedeme společné předky pro doklady a pro řádky takto:

 

  

Obrázek 1 Zavedení společného předka pro doklady a pro řádky dokladů

 

Poznámky k předešlému diagramu:

 

1.     Všimněme si, že struktura stromu dědičnosti pro řádky nekopíruje přesně strukturu stromu pro doklady, tj. nejsou zde specificky zavedeny například dědicové jako „řádek faktury“, „řádek objednávky“ atd. Důvod je ten, že některé typy řádků mohou mít stejnou strukturu pro několik typů dokladů a není tedy třeba zavádět pro každý typ dokladu specifický typ řádku. Jako příklad: Mohlo by nastat, že faktura i doklad mají stejný typ řádku, skladová výdejka má jiný typ řádku a skladová příjemka má stejný typ řádku jako výdejka.

 

2.     Stromy nemusí být jednoúrovňové a navíc mají v sobě prvky skládání kompozitů pro re-use stejných informací ve stromu. Vhodnou kombinací dědičnosti a skládání je docíleno toho, že větve stromů jsou disjunktní a nedochází k efektu kříženců (viz vzor Přemostění v uvedené knize), ale je přitom dosaženo maximálního re-use informace. 

 

3.     Každý prvek dědice dokladu musí moc dobře „vědět“, jaký typ řádku potřebuje a tedy jakého typu řádku si musí svůj řádek vytvořit anebo nechat vytvořit. Této požadované znalosti lze dosáhnout dvěma možnými způsoby: 

 

a.     Zavedeme podle vzoru Povolené kombinace asociační třídu mezi diskriminátory Typ dokladu a Typ řádku, v instanční rovině se založí dvojkombinace „typ dokladu versus typ řádku“, které udávají „kdo koho rodí“. Tyto záznamy jsou zamknuté pro uživatele a dají se měnit pouze servisním zásahem dodavatele informačního systému. Díky dvojkombinaci odkazů v prvku asociační třídy se pro daný prvek číselníku z Typu dokladu získá na druhé straně daný prvek číselníku Typ řádku a pak se nechá narodit takový řádek, který odpovídá danému kódu typu řádku z tohoto číselníku (v OOP například pomocí klasického vzoru FACTORY anebo PROTOTYPE, ve strukturovaném programování zakládáme nové struktury pomocí funkcí, které jsou umístěné ve switchi s větvením podle kódu typu řádku ).

 

b.     Využije se vzor FACTORY METHOD. Ve vrchní abstraktní třídě Doklad se zavede abstraktní metoda DejNovyRadek s návratovým typem Radek_Dokladu. Každý dědic dokladu tuto metodu implementuje tak, že přímo v kódu „natvrdo“ zavolá konstruktor odpovídající třídy dědice řádku a vydá nový řádek ven jako návratovou hodnotu.

 

K předešlému modelu přidáme vztahy mezi doklady a také vztahy mezi řádky podle nově zavedeného vzoru takto (2. stupeň vzoru, viz minulý článek):

  

Obrázek 2 Zavedení vztahů mezi doklady a vztahů mezi řádky

 

Poznámka: Toto řešení by bylo možné doplnit ještě o povolené kombinace mezi typy a zabránit tak nepovoleným kombinacím, viz předešlý článek - stupeň vzoru číslo 3, zde pro přehlednost není uvedeno.

 

Díky tomu, že asociační třída Doklad versus Doklad je nasazena na vrchní abstraktní třídu Doklad, můžeme nyní zavádět libovolné vztahy mezi libovolnými doklady libovolných podtypů (například, který doklad generuje který jiný, jako je například příjemka materiálu vystavená na základě objednávky materiálu apod.).

 

Podobně výhodná situace je nyní také mezi řádky, kde díky asociační třídě Radek versus Radek můžeme zavádět vztahy mezi řádky (který řádek faktury plní který řádek objednávky apod.).

 

Vztah mezi dokumenty různých typů

 

Velmi podobně bychom mohli zavést také vztahy mezi dokumenty v dokumentaci (například nabídka, jednání, zápis, apod.).  Podle našeho vzoru nasadíme vztahy mezi dokumenty takto:

 

Obrázek 3 Dokument versus dokument

 

Asi není třeba dodávat, že lze nyní vytvářet libovolné vztahy mezi dokumenty a že lze zavést také povolené kombinace mezi typy podle stupně 3 tohoto vzoru.

 

 

Možná úskalí při použití vzoru

 

Díky nasazení asociační třídy na abstraktní třídu jsme získali potřebnou flexibilitu, ale ta může být v některých případech spíše nevýhodou a nakonec nasazením vzoru můžeme více ztratit než získat. Tímto vzorem totiž převádíme původní vztahy „natvrdo“, které byly zavedeny mezi konkrétními třídami, na jeden flexibilnější vztah „nahoře“, tj. převedli jsme původní asociační třídy mezi dědici do flexibilnější roviny instancí.  Řečeno databázově všechny původní vztahy mezi dědici, tj. obsah několika různých asociačních tabulek, jsou nyní již v jedné tabulce „nahoře“ a jsou od sebe odlišovány pouze na úrovni záznamů, nikoliv tabulek, jak tomu bylo před nasazením tohoto vzoru. A to může v některých případech znamenat problém.  Uvedeme si proto možná úskalí a nebezpečí tohoto přístupu.

 

Problémy vztahů natvrdo

 

Může se stát, že i když nasadíme vzor Asociační třída na vrcholu stromu, přesto budou existovat vztahy mezi dědici, které do tohoto vzoru nezahrneme. Jsou to ty vztahy, které jsou dány analyticky vždy napevno a nutně musejí existovat. Jinak řečeno jsou to vztahy vždy napevno bez uživatelova rozhodování, nemají proto žádný požadavek stát se flexibilními.

 

Jako typický příklad bych uvedl vztah, kdy každá evidovaná fyzická osoba podnikatel (tj. evidovaný živnostník) má odkaz na fyzickou osobu (obsahuje například RČ, jméno, příjmení atd.). Před nasazením vzoru „Asociační třída na vrcholu stromu“ vypadá odpovídající vztah mezi fyzickou osobou podnikatelem FOP a fyzickou osobou (FO) takto: 

 

Obrázek 4 Vztah FOP má odkaz na FO

 

V tomto modelu má každá fyzická osoba podnikatel (FOP alias OSVČ) odkaz na fyzickou osobu (FO).

 

Poznámka: V modelu není vyznačeno, že i na druhé straně vztahu je multiplicita jedna.

 

Zaveďme nyní vztah Subjekt versus Subjekt podle našeho vzoru „Asociační třída na vrcholu stromu“ takto:

 

Obrázek 5 Zavedení asociační třídy Subjekt versus Subjekt

 

Někoho by v této chvíli mohla napadnout tato myšlenka: Vztah FOP versus FO je nyní zbytečný, protože se dá zahrnout pod vztah Subjekt versus Subjekt s typem tohoto vztahu „FOP má FO“ a s omezující podmínkou „pouze jeden“ pro dané instance FOP a FO.

 

Doporučení tohoto odstavce zní: Nedělejte to. Tento vztah „FOP vidí FO“ je totiž vztahem takříkajíc „natvrdo“, budeme jej zakládat vždy a bez uživatelova rozhodnutí. Naprogramovat jej nahoře mezi flexibilně zaváděnými vztahy je složitější než dole a navíc systém bude zbytečně pomalejší. Tento vztah tedy nepatří do naší hry na flexibilitu, kterou chceme nasazením vzoru získat a proto jej necháme dole tak je.

 

Problém příliš vysokého předka  

 

Když se podrobněji podíváme na aplikace tohoto vzoru specielně u příkladů s dokladem a dokumentem, mohla by někoho napadnout další myšlenka:

 

Oba modely, jak strom doklad, tak strom dokument, používají asociační třídu na vrcholu stromu, takže kdybychom zavedli ještě vyšší vrchol, tak bychom si ušetřili jedno nasazení tohoto vzoru takto: 

 

 

Obrázek 6 Příliš vysoký předek

 

 

Doporučení tohoto odstavce zní: Nedělejte to. 

 

Tímto postupem bychom smíchali dohromady to, co k sobě již nepatří a celý problém by se již stal nejen na programování a hlavně na testování již příliš složitý. Smíchali bychom dva do sebe rozdílné typy a evidovali je na jedné hromadě.

 

Poznámka: Teoreticky vzato, takto bychom mohli pomocí „superpředka“ zavést „superuniverzální asociační třídu“ na všechno J.

 

Nevytvářejme příliš vysokého předka, vrchol stromu nasadíme tam, kde má ještě pojmově smysl jako zástupný pojem.

 

Pokud však existují vztahy mezi dvěma vrcholy stromu, tj. v předešlém příkladu pokud existuje vztah mezi dokumenty a doklady, zaveďme za tím účelem asociační třídu mezi oběma vrcholy takto:

 

Obrázek 7 Asociační třída mezi vrcholy stromu

 

V tomto řešení by tedy po nasazení našeho vzoru existovaly celkem tři asociační třídy: Dokument versus Dokument, Dokument versus Doklad a Doklad versus Doklad. (poznámka: předešlý nepříliš šťastný návrh dal všechny tyto třídy na jednu hromadu).

 

Dědičnost v asociační třídě na vrcholu stromu

 

Může se stát, že pro jiné typy vztahů v asociační třídě na vrcholu stromu se evidují jiné informace. V tom případě lze zavést generalizaci i pro tuto třídu takto:

 

Obrázek 8 Možná generalizace v asociační třídě

 

Buďme však opatrní na přílišnou složitost tohoto stromu. Pokud se totiž strom příliš „rozkošatí“, potom ztrácíme výhody flexibility tohoto vzoru.

 

Zkušenost s použitím tohoto vzoru v praxi ukazuje, že dokud můžeme ještě stále zavést jednoduchého a přehledného „kočkopsa“, má smysl vzor „Asociační třídy na vrcholu stromu“ použít (o „kočkopsovi“ v generalizaci viz uvedená kniha Analytické modelování pomocí UML v praxi anebo podrobněji v našich školeních pobytových nebo internetových). Jedná se o ty situace, kdy většina evidované informace ve stromu je zavedena v předkovi a dědicové se liší od sebe velmi málo (například jedním dvěma atributy). Jakmile se však dědicové začnou od sebe příliš lišit, je výhodnější tento vzor opustit a vztahy nasadit pomocí asociačních tříd přímo mezi dědici „dole“ a nikoliv na vrchol stromu.  

 

Konec článku