Szkeleton tervezése 100 – Generalis faliora Konzulens:
Szabó András
Csapattagok: Kenéz Tamás Kiss Gergely Papp Gergely Rostás Gábor
TLSXNP KNJU43 L584UF N7WH3P
[email protected] [email protected] [email protected] [email protected]
2005. március 21.
A szkeleton modell valóságos use-case-ei A csomag felrobbanása
Feladata: a romlandó csomag felrobbanásának lekezelése. Működése: amikor a bejövő teherautó a romlandó csomagot átadja az első futószalagnak vagy váltónak, akkor beállít egy időzítést a csomaghoz a Timer objektumban. Az időzítés lejártakor a Timer meghívja a csomag timeOutAction() metódusát, aminek hatására a csomag beállítja a blown flagjét igazra. A futószalag a flag-et a következő frissítéskor érzékeli, és eltávolítja a csomagot magáról.
A csomag átadása: IT-C, C-C, C-OT use-case-ek
Generalis faliora
-2-
2005. március 21.
Feladatuk: a csomag továbbítása a bejövő teherautóról egy Container-be, Container-ből Container-be, illetve Container-ből kimenő teherautóra. Működésük: teljesen hasonlóak, ha a csomagot aktuálisan tartalmazó objektum észleli, hogy a csomag a következő frissítéskor leesne róla, a csomagot átadja az őt követő pályaelemnek annak addPackage() metódusának meghívásával. Ezután a csomagot eddig tartalmazó pályaelem meghívja a saját removePackage() metódusát, és eltávolítja magából a csomagot.
A csomag összetörése
Generalis faliora
-3-
2005. március 21.
Feladata: Annak az eseménynek a lekezelése, amikor egy csomagra ráesik egy másik csomag. Működése: amikor a bejövő teherautó vagy egy Container típusú objektum a csomagot átadja a rákövetkező futószalagnak vagy váltónak, akkor a fogadó fél ellenőrzi, hogy nem tartózkodik-e másik csomag ott, ahová az új csomag érkezik. Ha igen, akkor a „régi” csomag broken flagjét igazra állítja be; a csomag a következő frissüléskor fog eltávolítódni a modellből.
Időzítés a modellben
Feladata: a modell elemeinek időzítése. Működése: az első időzítést a Model szülőobjektum állítja be a Timer-en, az Initialization use-case során. A további időzítéseket a pályaelemek maguk állítják be (a Timer objektum
addWatch()
metódusának
segítségével)
az
első
időzítés
(timeOutAction()) lefutásának eredményeként.
Generalis faliora
-4-
2005. március 21.
Kimenő teherautó megtelése
Feladata: a megtelt kimenő teherautó modellben való megjelölése. Működése: a Container típusú objektum a szokásos módon adja a rákövetkező elemnek a csomagot. Mikor a kimenő teherautó érzékeli, hogy ő megtelt, azaz elfogyott a rendelkezésre álló kapacitása, akkor az available flagjét hamisra állítja.
Generalis faliora
-5-
2005. március 21.
Inicializáció
Feladata: a modell létrehozása, alapállapotba hozása. Működése: A Model szülőobjektum létrehozza a Timer időzítő objektumot (mely szingleton objektum a rendszerben), a Timer feladata a modell elemeinek időzítése. A Model objektum létrehozza a modell elemeit, létrehozza a bejövő teherautót, a futószalagokat, a váltókat, és a kimenő teherautókat. A bejövő teherautót feltölti a pályában definiált színű és minőségű csomagokkal. Mindezek után összelinkeli a pályának megfelelően a teherautókat, futószalagokat, váltókat azok setNextLine és setNextLines metódusai segítségével. Végül bejegyzi a Timer-ben a pályaelemek első időzítéseit. Ezek után a Model-t tartalmazó fő osztály és majd a grafikus és vezérlő komponensek folytathatják működésüket, a játék modellje inicializálva van.
Generalis faliora
-6-
2005. március 21.
Kollaborációs diagramok A csomag felrobbanása
Csomag átadása: IT-C, C-C, C-OT kollaborációs diagramok
Generalis faliora
-7-
2005. március 21.
A csomag összetörése
Időzítés a modellben
Generalis faliora
-8-
2005. március 21.
Kimenő teherautó megtelése
Az inicializálás kollaborációs diagramja
Generalis faliora
-9-
2005. március 21.
Az információk kijuttatása a modellből Csapatunk úgy döntött, hogy az információk kijuttatása egy EventStore nevű tárolón keresztül történjen. Ez az objektum nem része a modellnek, mert csak a külvilággal való kapcsolódás biztosítása a feladata, azonban éppen ezért minden a külvilágra hatást gyakorló modellbeli objektumnak ismernie kell őt. Működése: a modell által megszűnésre ítélt objektumokat saját maguk, vagy valamelyik másik objektum beregisztrálja az EventStore egyik listájába, a modellbeli referenciák ezután megszűnnek. A modell frissítésekor csak ezeket a listákat kell ellenőrizni (melyeknek a hossza az esetek túlnyomó többségében nulla). Ezután pedig a listákban található objektumokon végrehajtható a szükséges művelet (például effektek: teherautó kimegy a pályáról, csomag felrobban). Amiért azonban ez a fejlesztés szükségszerű volt: megszüntethető az objektum wrappere, és így az objektum maga is végleg megszűnhet.
Megjegyzés A program működésében a modell helyességén túl a külvilággal megvalósított kapcsolat is létfontosságú. Ezt a működést a use-case-ektől különválasztva, egy diagramba sűrítve ábrázoltuk. Ennek az információnak a többi use-case-be építve kellene szerepelnie, azonban ez nem a modell része, csak egy csatolási pont. Továbbá azért is célszerűbb így ábrázolni, mert így áttekinthetőbb. A fent említett okok miatt sincs a use-case-ek leírásánál külön-külön mindenhol megemlítve hogy a flagek állítása mellett ezeket a függvényeket is meghívjuk. A szekvencia-diagramban a nyilak sorrendje most nem jelöl eseménysorrendet, csak azt, hogy melyik objektum milyen hívással fordulhat az EventStore tárolóhoz (különkülön mindegyik variációt célszerűtlen lett volna felrajzolni). Ugyanígy az ehhez tartozó kollaborációs diagramban sem szerepelnek az események sorrendjét jelölő sorszámok.
Generalis faliora
- 10 -
2005. március 21.
Generalis faliora
- 11 -
2005. március 21.
Hibajavítás – avagy az eddigi dokumentációkkal való ellentmondások feloldása A múlt héten leadott dokumentációban említettük, hogy megfontoltuk, hogy nem kell a modellbe az a bizonyos univerzális „csomag-evő” objektum, amely a kimenő teherautó helyett állt volna be egy futószalag végére. Azóta rájöttünk, hogy ez megoldható egy sokkal egyszerűbb módosítással, mégpedig a következő módon. Az Out_Truck működése eredetileg külön volt választva a csomag leesésétől. A kimenő teherautó a modellben sosem fog eltűnni a futószalag végéről, csak az avaiable flag állásában (meg persze a megjelenítésben) lesz különbség. Ha egy csomag avaiable=false
állású
teherautóra
adódik
át,
akkor
összetörik,
ha
avaiable=true-ra akkor csak egyszerűen megszűnik. Az EventStore-os megoldással együtt így objektum-orientáltabb (és gyorsabb) üzenet-alapú működést érünk el a modell és a modellt vezérlő/megjelenítő egység határán. Egy másik hibánk volt, hogy az Out_Truck-ba nem vettünk fel capacity számlálót is, holott a specifikációban az szerepelt. Ezt kifelejtettük a statikus struktúradiagramból, de a legfrissebb verzióban már javítottuk ezt. Még egy hiba, amit a modell analizálása során találtunk: az előbbi kimenő teherautó – csomagevő objektummal sikerült azt az ellentmondást belevinni a modellbe, hogy a csomag leesését kétféleképpen is definiáltuk. A régebbi megoldás az volt, hogy az utolsó futószalag öli meg a csomagot; az új viszont az, hogy a teherautó öli meg a csomagot (persze az EventStore-on keresztül a wrapperével együtt). Úgy döntöttünk, hogy a második megoldás marad a végleges, így a csomag leesése usecase diagramot és kollaborációs diagramot töröltük a dokumentációból. Ez egyszerűen csak egy Container–Out_Truck drop művelet lesz, a többiről majd a teherautó gondoskodik (mivel a futószalag nem fogja tudni, hogy milyen flagű teherautónak adja tovább a csomagot) – az EventStore-os diagramokon látható módon.
Generalis faliora
- 12 -
2005. március 21.
A szkeleton kezelői felületének terve, dialógusok A szkeleton célja az analízis modellben felvázoltak helyes működésének igazolása. Azért, hogy ez a helyesség a felhasználó által is ellenőrizhető legyen, egy parancssoros (konzolos) felületet biztosítunk. A szkeleton a modellnek semmilyen állapotát nem tárolja, ezért a felhasználónak kell minden szükséges információt bevinnie. Amikor a szkeleton bemenetet vár, akkor körülírja, hogy pontosan milyen információra van szüksége a működés folytatásához. A szkeleton mindig felkínálja az éppen aktuális választási lehetőségeket a felhasználónak, aki a numerikus billentyűzetet használva kiválasztja a neki megfelelő opciót. A függvények meghívódását és befejeződését kijelzi a szkeleton. Ha egy függvény a felhasználó által szolgáltatott bemenet közvetlen hatására hívódik meg, akkor ezt a függvény előtt egy * szimbólum jelöli. A függvényhívások mélységét szóközök használatával szemléltetjük. Egy függvény hívását a függvényt tartalmazó objektum neve előtti + jellel, a hívás visszatérését ugyanott egy – jellel jelöljük. Ennek megfelelően a megjelenítés formátuma a következő lesz: [szóközök][*]+Osztály:függvény(attrib1, attrib2, …) [szóközök][*]–Osztály:függvény Amikor a szkeleton választás elé állítja a felhasználót, akkor ezt a kérdés előtt egy „>>” jellel jelöljük, ami a kérdés minden sora előtt szerepel, a válaszlehetőségek sorait is beleértve. Minden válasz mellett szerepelni fog egy sorszám, a felhasználónak ezt a sorszámot kell begépelnie, és utána az Enter billentyűt lenyomnia a választás véglegesítéséhez. Például: >> Hova továbbítódjon a csomag a futószalagról? >> 1. Kimenő teherautóba >> 2. Másik futószalagra >> 3. Váltóra >> 4. Földre >> Generalis faliora
- 13 -
2005. március 21.
Architektúra A szkeleton feladata az analízis modellben megfogalmazott use-case-ek helyes működésének igazolása, ennek megfelelően a tényleges implementáció a modell működésére koncentrál, a control és a view rész a lehető legegyszerűbb, minimális. A szkeleton ezért statikus objektumokből fog állni, minden objektumból lesz egyetlen példány, a kérdéseket egy központi objektum teszi fel, a válaszok eredményének megjelenítését szintén egy közös objektum végzi. A szkeleton nem modellez, csak igazol, minden felmerülő kérdésre a felhasználótól kapja meg a válaszokat. Ezzel szemben a tényleges projektnek sokkal sokrétűbben kell majd működnie, itt a feladat a modell inicializálása előre megadott pályaadatok alapján, a modell ütemezése és vezérlése, illetve a grafikus megjelenítés.
A program vázlatos szerkezete A játékot egy fő osztály valósítja meg, ennek feladata a különböző menük összefogása, a játéktér hozzáadása lesz. A játéktér tartalmaz egy példányt a modellünkből, illetve ez tartalmazza majd azt a fő szálat, mellyel az ütemezést végezzük, valamint ez kéri a kirajzolást a modelltől valamilyen grafikus felületre.
A modell szerkezete A modell elemeit egy Model nevű objektum fogja egységbe, azonban nem kezeli monolitikusan a modellt, azt közvetlenül nem ismeri. Feladatai csupán a kezdőállapot létrehozása (inicializálás) és a modell kimeneti-bemeneti pontjainak kezelése a wrapperek segítségével. A wrapperek olyan kiegészítő információkat tartalmaznak a modell egyes elemeiről, melyek típusukból adódóan nem lehetnek részei a modellnek (pl koordináták, kirajzolási utasítások), különben elmosódna a határ az absztrakt modell és a valóságos implementáció között, ami később súlyos tervezési nehézségekhez vezetne. Csatolások a modellben: a modell legelső eleme a bejövő teherautó. Ez az elem meghatározott időközönként (belső ütemezés), kiad egy csomagot a hozzá csatolt futószalag-
Generalis faliora
- 14 -
2005. március 21.
ra/váltóra. A futószalag kimenete csatlakozhat másik futószalaghoz, kimenő teherautóhoz vagy váltóhoz, a futószalagok felelőssége a csomagok tárolása és a megadott irányba lökdösése. Ennek megfelelően a futószalag tartalmazni fog egy csomaglistát, ahova a pálya többi eleme bejegyezhet csomagokat. A váltók több futószalaghoz is kapcsolódnak, de egyszerre mindig csak egy kapcsolat aktív (amerre a váltó mutat). A modell „végei” a kimenő teherautók, ezek egy-egy futószalag (esetleg váltó) végpontjai.
Ütemezés A program egyetlen fő szálon fog futni, melynek célja a modell frissítése és a kirajzolás. Mivel a model-view-controller szemlélet szerint a modellt különválasztottuk a kirajzolástól, ezért a szálat kezelő objektum egy fő objektum lesz, amely összehangolja a modell, a megjelenítés és a vezérlés működését és minden ütemezési feladatot ellát. A modell saját belső ütemezést használ, melyet a Timer objektum valósít meg, méghozzá aszinkron módon. Ez azért előnyös, mert így kikerülhető a modellben egy monolitikus ütemező objektum használata, ezáltal a modell valóságosabb, megbízhatóbb működést garantál. Azonban a főprogramban egyszerűbb a monolitikus kezelés használata a megjelenítés és a vezérlés miatt. Az ütemezés minél egyszerűbbé tételéhez itt csak egy szálat használunk. Több szál használata is lehetséges lenne, ez azonban szinkronizációs problémákhoz vezetne és így a program is bonyolultabb lenne, mindamellett nem működne hatékonyabban.
Generalis faliora
- 15 -
2005. március 21.
Napló A napló tartalmazza, hogy az egyes csapattagok mit és mikor tevékenykedtek a projektért.
2005.03.16. 16-18.
Kenéz, Kiss, Papp, Rostás
Megbeszélés, a heti feladatok kiosztása
2005.03.17. 14-17.
Kenéz, Kiss, Papp, Rostás
Szekvencia-diagramok megrajzolása
2005.03.17. 17-19.
Kenéz, Kiss, Papp, Rostás
Hivatalos megbeszélésen való részvétel
2005.03.17. 20-21.
Kiss, Papp
Online konzultáció
2005.03.18. 13-16.
Kenéz, Kiss, Papp, Rostás
Kollaborációs diagramok megrajzolása
2005.03.19. 21-23.
Kenéz, Rostás
Szkeleton kezelői felület tervének megírása
2005.03.19. 22-23.
Kiss
Architektúra rész megírása
2005.03.19. 23-24.
Papp
Dokumentumszerkesztés
2005.03.20. 16-17.
Papp
Dokumentumszerkesztés
2005.03.20. 20-22.
Kiss, Papp
Online konzultáció
2005.03.20. 22-23.
Papp
Dokumentumszerkesztés
2005.03.20. 23 – 2005.03.21. 02.
Generalis faliora
Kiss, Papp
A felmerülő kérdések online megbeszélése, a dokumentum csiszolása, a hibák kijavítása
- 16 -
2005. március 21.