Jak co nejefektivněji vyjádřit větvení ve scénářích případů užití

 

 

autor: RNDr. Ilja Kraval, říjen 2010

 

http://www.objects.cz

 

 

Úvod

 

Při tvorbě Use Case modelu se doporučuje, aby se u každého případu užití napsal scénář chodu programu jako zadání pro kódování.

 

Analytik kromě jiného popisuje ve scénáři také větvení. Otázkou však je, jak toto větvení nejlépe vyjádřit.

 

Je vcelku méně známé, že pro větvení programu lze použít dvě možné techniky zápisu, které odpovídají dvěma možným filosofiím:

 

·        vyjádření větvení pomocí strukturovaného přístupu, které je zastaralejší a méně přehledné, a které využívá techniku přepínače (obdoba příkazu switch resp. select case v programu)

 

·        vyjádření větvení pomocí efektivnějšího objektového přístupu využívajícího polymorfismus

 

Právě tomu druhému, efektivnějšímu a přehlednějšímu způsobu větvení bude věnován tento článek. Je třeba podotknout, že článek nemůže obsáhnout všechny aspekty a případné nejasnosti při použití efektivního způsobu psaní scénářů, proto je také této problematice věnována náležitá pozornost ve výkladu a cvičeních na našich pobytových školeních.

 

Strukturovaný způsob větvení ve scénářích případů užití

 

Zastaralejší strukturovaný způsob větvení není třeba příliš vysvětlovat (protože se hojně používá). Uvedeme si jej zde proto, abychom jej mohli porovnat s technikou efektivnějšího objektového polymorfního zápisu.

 

V našem prvním příkladu vyjděme ze známého vzoru Party pro evidenci osob (mimochodem tento již klasický vzor je také velmi podrobně vysvětlen na našich pobytových školeních). Nechť se pomocí tohoto vzoru v systému evidují dva typy osob: fyzická osoba a právnická osoba, což pomocí vzoru Party vyjádříme takto:

Obrázek 1 Detail vzoru Party

 

Zavedení společného abstraktního předka Osoba pro oba typy osob umožňuje využít základní vlastnost Generalizace a tou je tzv. zástupnost rolí zespodu nahoru, kterou můžeme vyjádřit takto:

 

Díky Generalizaci všude, kde se na konci asociace vyskytuje v nějaké roli předek (zde abstraktní třída Osoba), lze do této role předka v instančním modelu technicky dosadit libovolnou instanci z konkrétního potomka (zde instance třídy Fyzická osoba a instance třídy Právnická osoba).

 

V našem modelu to konkrétně znamená, že všude, kde se vyskytuje na konci asociace v nějaké roli třída Osoba, může tuto roli na dané pozici sehrát instance z Fyzické osoby a instance z Právnické osoby.

 

Je zřejmé, že v dynamickém chování scénářů v případech užití bude zapotřebí nějak vyjádřit větvení, které se týká rozdílného chování instancí různých typů, tj. jinak bude vypadat nějaký scénář zpracování pro fyzickou osobu a jinak pro právnickou osobu.

 

Podívejme se na následující obrázek a představme si, že držíme v ruce instanci ze třídy Klient, která si ukazuje na horní třídu Osoba:

 

Obrázek 2 Klient používá Osobu, tedy klientem může být jak FO tak PO

 

Nyní potřebujeme zobrazit údaje osoby tohoto klienta. Je vcelku logické a pochopitelné, že dané scénáře pro zobrazení údajů se budou lišit podle toho, zda se na konci asociace bude v běhu programu vyskytovat instance ze třídy Fyzická osoba (v tom případě se zobrazí např. rodné číslo, jméno, příjmení) anebo instance ze třídy Právnická osoba (v tom případě se zobrazí např. IČ, název firmy, DIČ apod.)

 

Nechť se v našem příkladu celý případ užití nazývá Identifikace klienta (poznámka: tento případ užití je volán v kontextu jiných případů užití, například založení služby apod.). Scénář tohoto případu užití pak vypadá například takto:

 

UC Identifikace klienta

Obsluha zadá unikátní číslo klienta, podle tohoto čísla se v seznamu nalezne klient, pokud nenalezen, err1.

Dále se provede UC Zobrazení údajů osoby.

 

V poslední větě scénáře jsme se odvolali na případ užití nazvaný Zobrazení údajů osoby pomocí interakce include. Tento volaný případ užití pak bude mít ve svém scénáři zmíněný přepínač podle typu osoby:

 

UC Zobrazení údajů osoby

Pokud je typ osoby fyzická osoba, provede se UC Zobrazení údajů fyzické osoby

Pokud je typ osoby právnická osoba, provede se UC Zobrazení údajů právnické osoby 

 

V USE CASE DIAGRAMU bychom tuto situaci znázornili takto:

 

Obrázek 3 Větvení přepínačem s include

 

Uveďme si pro názornost další příklady větvení podle stejného schématu:

 

UC Spouštění akcí s výběrem akce

Obsluze se zobrazí seznam akcí, obsluha vybere akci a spustí ji, viz UC Spuštění akce

 

UC Spuštění akce

Pokud byla vybrána akce „Akce 1“, provede se UC Spuštění Akce 1

Pokud byla vybrána akce „Akce 2“, provede se UC Spuštění Akce 2

atd.

 

Poznámka: Názvy akcí v předešlém scénáři odpovídají samozřejmě reálným názvům, například odsouhlasení faktury, založení klienta apod.

 

Mnohdy výběr ve větvení nemusí provádět pouze obsluha, ale i sám program, například takto:

 

UC Zpracování došlých zpráv

Systém zpracovává došlé zprávy. U každé zprávy se zjistí její typ a provede se UC Zpracování zprávy. 

 

UC Zpracování zprávy

Pokud je typ zprávy typ 1, provede se UC Zpracování zprávy typu 1

Pokud je typ zprávy typ 2, provede se UC Zpracování zprávy typu 2

 

atd.

 

Na první pohled by se mohlo zdát, že větvení strukturovaným způsobem se jeví jako přehledné a flexibilní, ale není tomu tak.

 

Za prvé, zvolili jsme opravdu jednoduché příklady s menším počtem větví (účelově z čistě pedagogických důvodů pro snazší vysvětlení příkladů). Proto se jeví přepínače na první pohled jako přehledné, což je v praxi spíše výjimkou.

 

Za druhé a to je důležitější, pokud dalším vývojem odhalíme novou větev, tj. v předešlých příkladech se zavede nový typ osoby resp. se zavede nová akce a její spuštění anebo nový typ zprávy s novým zpracováním, pak narazíme na následující problém:

 

Při přidání nové větve musíme povinně otevřít existující případ užití, ve kterém se vyskytuje scénář větvení s přepínačem a „překopat jej“, tj. přidat novou větev a popsat ji. Všimněme si, že přidání nového způsobu zpracování vede k zásahu do „starého scénáře“, tj. původní „aditivnost“ funkcionality vede k „update“ starého scénáře, což indikuje nějakou nečistotu a nikoliv 100% re-use.

 

Existuje jiný, sice méně známý, ale efektivnější způsob pro vyjádření větvení, a ten si teď ukážeme a vysvětlíme. 

 

Efektivnější objektový způsob větvení v USE CASE DIAGRAMU pomocí polymorfismu

 

Jazyk UML zavádí vztah Generalizace nejenom pro třídy, ale kromě jiných typů v UML i pro případy užití. Jedná se de facto o úplně stejný a tentýž vztah, jako je zaveden pro třídy, ale je aplikován na případy užití. Znamená to, že vše, co v Generalizaci platí pro třídy a její instance, platí také pro případy užití a jejich zavolání. Generalizace jako jeden vztah se pro případy užití maluje stejně jako v modelu tříd, samozřejmě vyjadřuje totéž a také se chápe stejně, jenom namísto o třídách hovoříme o případech užití.

 

Jedinou otázkou zde je, k čemu se dá Generalizace v modelu případů užití prakticky využít. A právě v odpovědi na tuto otázku se skrývá řešení zápisu efektivnějšího větvení scénářů založeného na objektově orientované filosofii.

 

Představme si, že autor USE CASE MODELU namaloval následující obrázek:

Obrázek 4 Generalizace mezi případy užití

 

Nejprve si připomeňme větu zástupnosti rolí v Generalizaci, použijeme ji však pro případy užití:

 

Díky Generalizaci všude, kde se na konci include vyskytuje v nějaké roli případ užití předek, lze do této role předka technicky dosadit libovolnou instanci z konkrétního případu užití potomka.

 

A nyní si za pomoci této věty předešlý obrázek rozebereme:

 

1. Actor Obsluha používá případ užití X a tento případ užití má nějaký svůj scénář.

 

2. Uvnitř tohoto scénáře X dojde k odvolání se na případ užití A, zřetelně totiž vidíme include z X do A. Znamená to, že někde ve scénáři X se objeví takováto nebo podobná formulace: „a dále se použije UC A.“

 

3. Případ užití A je abstraktní (název tohoto případu užití je zřetelně písmem Italic) a tedy nebude nikdy instanciován, i když se na něj odvolává scénář v X.

 

4. Generalizace znamená, že tam, kde v include vystupuje abstraktní předek, bude dosazena konkrétní instance potomka. Znamená to, že ve scénáři X v místě odvolání se na případ užití A bude konkrétně zavolán v běhu scénáře jeden z potomků - buď případ užití B anebo C, které mají díky Generalizaci jako instance schopnost nahradit předka v pozici jeho zavolání. Který z potomků to bude, je dáno větou ve scénáři, která specifikuje, podle čeho má být daný případ užití jako potomek vybrán.

 

Tomuto jevu, kdy se odvoláváme na určité chování jako zástupný pojem funkcionality (například ve scénáři „a teď vybrané zvíře vydá zvuk“), ale přitom máme mysli několik možných konkrétních realizací a z nich se některé dá nějak zvolit („zaštěkání psem, zamňoukání kočkou“), se obecně nazývá polymorfní chování.

 

Princip je tedy zřejmý: Odvoláváme se sice na případ užití A, ale konkrétně se tam provede jeden z potomků, tj. zde B nebo C. Horní případ užití se tak stává pouze zástupným pojmem pro zavolání potomků v daném bodě.

 

Poznámka: Pro ty z vás, kteří už někdy v objektově orientovaném programování překryli „vrchní“ abstraktní metodu předka konkrétní metodou potomka, není třeba tuto situaci dále příliš podrobně vysvětlovat, je to stejné podstaty a dokonce by bylo žádoucí, aby se v objektové technologii daný scénář takto i realizoval, tedy nikoliv pomocí přepínače.

 

Jak si nyní ukážeme, formulace s Generalizací je mnohem jednodušší a flexibilnější, než jak je tomu u klasického strukturovaného přepínače.

 

Vraťme se tedy k našemu příkladu se zobrazením údajů osoby a přeformulujme větvení pomocí polymorfismu. V tomto případě se konstrukce malinko změní: Nezavedeme žádný klasický přepínač (switch), ale v modelu zavedeme Generalizaci takto:

 

Obrázek 5 Řešení pomocí Generalizace

 

Už na tomto obrázku je vyjádřena následující skutečnost a tu si hned v duchu představme: Někde ve scénáři UC Identifikace klienta je zavolání UC Zobrazení údajů osoby, což je v Generalizaci abstraktní předek. To znamená, že bude vybrán případ užití jednoho z konkrétních potomků, zde buď  Zobrazení údajů fyzické osoby anebo Zobrazení údajů právnické osoby, a tento vybraný případ užití se „zespodu vtlačí“ do tohoto volání namísto abstraktního případu užití Zobrazení údajů osoby.

 

Scénář s polymorfním chováním pak vypadá takto:

 

UC Identifikace klienta

Obsluha zadá unikátní číslo klienta, podle tohoto čísla se v seznamu nalezne klient, pokud nenalezen, err1.

Dále se provede UC Zobrazení údajů osoby podle typu osoby.

 

Oproti předešlému strukturovanému scénáři došlo k těmto dvěma výrazným změnám: V textu se objevil důležitý dovětek „podle typu osoby“. To udává, jak bude vybrán potomek a dosazen do bodu odvolání se na případ užití Zobrazení údajů osoby.

 

Druhá a velmi důležitá změna: Případ užití Zobrazení údajů osoby je zde abstraktní a dokonce úplně prázdný případ užití. Neobsahuje nic (žádný přepínač!), on totiž pouze zastupuje pojmově svoje potomky, kteří mohou být vybráni a na jeho místo dosazeni. Ono požadované větvení je nepřímo skryto právě ve zmíněném dovětku „podle typu osoby“, který říká, že jeden z potomků bude vybrán a dosazen na místo zavolání předka. Důležité je pochopit, že již nikde nespecifikujeme žádný přepínač, tedy žádné „pokud…tak“!

 

V našem příkladu tedy musíme popsat ve scénářích tyto případy užití (viz předešlý obrázek)

 

UC Identifikace klienta (obsahuje odvolání na prázdný UC Zobrazení údajů osoby)  

UC  Zobrazení údajů fyzické osoby

UC Zobrazení údajů právnické osoby

 

a žádný jiný v tomto případě nepopisujeme, tj. UC Zobrazení údajů osoby již nemusíme popisovat, je totiž prázdný!

 

Je možná i jiná formulace, která je však již pro laika hodně nesrozumitelná:

 

Dále se provede jeden z potomků UC Zobrazení údajů osoby podle toho, o jaký typ osoby se jedná.

 

Tato formulace je oproti předešlé pro znalé Generalizace v UML sice hodně názorná, ale má tu nevýhodu, že laik zde absolutně nechápe, proč se najednou hovoří o nějakých potomcích.

 

Doporučuji tyto dvě možné formulace, můžete si vybrat:

 

Dále se provede UC Zobrazení údajů osoby podle typu osoby

 

anebo rozvláčnější

 

Dále se provede UC Zobrazení údajů osoby podle toho, o jaký typ osoby se jedná

 

Podobně vyřešíme i naše další příklady větvení s akcemi a zprávami.

 

UC Spouštění akcí s výběrem akce

Obsluze se zobrazí seznam akcí, obsluha vybere akci a provede se UC Spuštění akce podle vybrané akce.

 

Zde se stává abstraktním a tedy „zástupným“ případem užití Spuštění akce a ten má konkrétní dědice Spuštění akce 1, Spuštění akce 2 atd.

 

 

UC Zpracování došlých zpráv

Systém zpracovává došlé zprávy. U každé zprávy se zjistí její typ a provede se UC Zpracování zprávy podle typu došlé zprávy. 

 

Zde se stává abstraktním a tedy „zástupným“ případem užití Zpracování zprávy a ten má konkrétní dědice, Zpracování zprávy typu 1, Zpracování zprávy typu 2 atd. 

 

 

Závěr

 

Všimněme si těchto dvou velkých výhod zápisu větvení pomocí objektové filosofie, které činí uvedený objektově orientovaný postup maximálně efektivním:

 

1. Nemusíme vypisovat nějaký složitý přepínač, ten nám odpadl díky přehledné konstrukci znázorněné diagramem pomocí Generalizace

 

2. Pokud se přidá další možnost větvení, potom stačí přidat potomka do vztahu Generalizace a nic víc. Zápis je maximálně flexibilní vůči přidání další větve, stačí pouze přidat případ užití jako dalšího potomka. 

 

Tyto dvě výhody činí z polymorfního zápisu větvení scénářů evidentně více efektivní postup, než klasický strukturovaný přepínač.

 

 

Konec článku