Kdy použít v Use Case Diagramu vztah Extend a kdy Include (část 4)

V této části mini seriálu o interakcích Extend a Include v Use Case Diagramu si ukážeme, jak se tento vztah chápe jako zadání do technologického návrhu a programování.

V případě nasazení vztahu Include je mapování do technologie a následně do programování jednoduché. Nechť analytik odevzdal zadání do programování jako vztah Include např. takto:

   

Pro technologa a programátora z toho plyne požadavek, že ta část kódu, která bude realizovat funkčnost případu užití Use Case A bude přímo (tj. “natvrdo”) volat nějakou funkčnost v kódu, který realizuje případ užití Use Case B. Toho lze jednoduše dosáhnout přímým voláním některé z metod objektu (resp. funkce v neobjektovém prostředí), která bude naprogramována v části kódu, který realizuje případ užití Use Case B.

Pokud však analytik odevzdá model se vztahem Extend, např. takto:  

 

tak tím autor modelu zadal do programování, že případ užití Use Case X nebude přímo volat Use Case Y, ale že případ užití Use Case X pouze pro extenzi nabízí nějakou službu (v Use Case Diagramu jako Extension Point, na obrázku není znázorněn). K této službě se může extendující případ užití připojit a být vyvolán, aniž by případ užití Use Case X “věděl”, koho vyvolává. 

K realizaci tohoto požadavku v programování musí kódér využít některou ze speciálních technik programování, což může být např. :

  • polymorfismus pomocí zavedení překrytí metody (override)
  • polymorfismus pomocí zavedení delegátů
  • volání funkce přes pointer
  • volání funkce přes proměnnou typu funkce
  • řešení pomocí událostí v systému resp. přes Message Queue Server

To vše zkušený technolog resp. programátor zná prakticky velmi dobře. Jenže analytik často komunikuje s laikem a pak nastává problém, jak vysvětlit tyto techniky laikovi tak, aby dotyčný pochopil, co vlastně Extend znamená v programátorské praxi a proč se používá.

Nabízí se jeden velmi jednoduchý způsob realizace vztahu Extend, který je velice názorný a pro laika pochopitelný. Tuto techniku realizace Extend si nyní vysvětíme.

Poznámka: Z určitých důvodů se dále uvedený způsob nedoporučuje (i když je velice názorný) a v článku si také uvedeme proč.

Většina prostředí poskytuje zvláštní funkci (resp. objekt s metodou) zvanou CallByName. Jedná se o jakousi “univerzální” funkci, která má ve vstupním parametru název nějaké jiné existující funkce (resp. název metody objektu). Funkce CallByName převezme název funkce jako vstupní parametr, nalezne funkci s tímto názvem v existujících definovaných funkcích a spustí ji. Je zřejmé že sama funkce CallByName “neví”, co vstupní string obsahuje, je to dynamická proměnná, takže sama “neví”, co spouští.

Poznámka: Tato funkce byla zavedena např. ve starších verzích Visual Basicu, její ekvivalent nalezneme také v .NET Framework, viz např. zde. Je zřejmé, v čem je nevýhoda použití této funkce: Pokud pošleme jako vstupní parametr název funkce “Ahoj” (a taková neexistuje), tak chyba se zjistí až za běhu programu v runtime. Překrytí metody anebo nasazení  delegátů je více typově chráněno proti takovým chybám již při překladu resp. ještě dříve upozorněními v editoru s tzv. “intelligent code completion” (např. IntelliSense ve Visual Studiu apod.)

Pomocí této funkce lze jednoduše realizovat vztah Extend. Jako názornou ukázku tohoto postupu si pomocí funkce CallByName vyřešme příklad z předešlého článku, kde byl zaveden vztah Extend u případu užití řešícím zaúčtování převodního příkazu.

Analytik z  pochopitelných důvodů (vysvětleno v předešlém článku) odevzdal tento model s interakcemi Extend:

 

 

Jedno z možných technologických řešení je následující:

Zaveďme tabulku v databázi, nazvěme ji například Tab_On_Balance_Change.  Do této tabulky se budou ukládat názvy funkcí (resp. metod objektů), které budou vyvolány na změnu zůstatku. Každý modul, který potřebuje být zavolán na změnu zůstatku, zavolá modul zpracovávající převodní příkazy a pošle mu string s názvem funkce (metody). Modul převodních příkazů tento string převezme a uloží si jej do této tabulky.

V daném bodě programu při změně zůstatku se načtou všechny řádky této tabulky, cyklem se převezmou hodnoty názvů funkcí v nich obsažených a zavolá se funkce CallByName se vstupním parametrem právě načtené hodnoty na daném řádku. Všimněme si, že obsah tabulky je tvořen dynamicky, obslužný program tedy ani neví, koho volá, pouze převezme hodnotu a předá ji do funkce CallByName. Proto, pokud se přidá nový řádek s novou funkcí, náš program obsluhující změnu zůstatku nebude změněn.

Všimněme si, že celý proces probíhá ve dvou krocích: Jednotlivé moduly, které potřebují využít službu zavolání na změnu zůstatku, zavolají modul převodních příkazů pro přidání funkce a ten si přidá tuto funkci jako řádek do dané tabulky. Tomuto kroku se ve vzoru OBSERVER obecně říká “registrace”. Následně při změně zůstatku jsou všechny registrované funkce zavolány, tomuto kroku se říká “notifikace”.

Překrytí metody a nasazení delegátů funguje dost podobně, ale s tím podstatným rozdílem, že jsou vyžadována o mnoho striktnější pravidla typového programování, takže nelze dosazovat “jen tak volně” metody objektu do dané pozice zavolání jako v tomto příkladu.

Konec článku

   
Categories

About the Author:

správce a majitel Serveru objektových technologíí http://www.objects.cz

One Comment
  1. Miloš Š

    Jinak řečeno. UC X nabízí informaci “změnil se účet xxxx o MMM” a koho to zajímá, ať se zařídí.
    Takhle vypadá rozhraní – signatura metody, formát dat….
    Hezky to řeší registrace posluchačů, modulů nebo message-queue (tam je ale třeba určit, kdo a kdy záznam vymaže jako zpracovaný/prošlý.

0 Pings & Trackbacks

Leave a Reply