Programozás II. ATM példa Dr. Iványi Péter
1
ATM gép • ATM=Automated Teller Machine • Pénzkiadó automata • Kezelő szoftvert szeretnénk írni – Objektum-orientált módon
2
Követelmények • Egyszerre csak egy embert szolgál ki • Be kell tenni egy kártyát és be kell írni a PIN kódot – Ezeket majd a bank ellenőrzi
• Ezután több tranzakciót lehet végrehajtani • A kártyár csak akkor adjuk vissza ha befejezte a műveleteket
3
Követelmények • Tranzakciók – Lehessen kivenni pénzt az automatából – Lehessen lekérni a számlán levő összeget – A bankban mindig ellenőrizni kell hogy a tranzakció érvényes-e – Ha rossz PIN kódot gépeltünk be, három lehetőségünk van, ha harmadikra sem sikerült a gép megtartja a kártyát – Ha valamiért rossz a tranzakció a gép kijelzi 4
Követelmények • Egy operátor kikapcsolhatja és bekapcsolhatja a gépet • Kellene egy log (rögzítő) mechanizmus, ami mindent műveletet tárol • Számlát ad a műveletek után
5
ATM rendszer ATM
6
Események • Indítás – A rendszert be kapcsolja az operátor és feltölti pénzzel
• Leállítás – Ha nem használja senki a gépet ki lehet kapcsolni a gépet • Megszakad a kapcsolat a bankkal
7
8
9
Események • Session – Beraknak egy kártyát a gépbe – A gép behuzza és megpróbálja olvasni • Ha hiba van visszaadja
– – – –
Be kell gépelni a PIN kódot Menüből választva megadhatunk egy tranzakciót Minden tranzakció után megkérdezzük folytassuk-e Ha nem, ki kell adni a kártyát
10
11
Események • Tranzakció – Absztrakt osztály, mindegyik tranzakció egy kicsit más – Akkor használjuk amikor a menüből választottunk egy műveletet – A tranzakció adatait egy üzenetben küldjük el a banknak – Ha a bank jóvá hagyja, akkor végrehajtja az ATM – Ha a bank szerint rossz a PIN, újra be lehet írni, max háromszor
12
13
Események • Pénz kivétel – Bekérjük hogy mennyi pénzt akar kivenni – Ellenőrizzük, hogy van-e elég pénz a számlánkon – Ha igen • Ellenőrizzük, hogy van-e elég pénz az automatában
– Ha minden rendben kiadjuk a pénzt
14
Események • Lekérdezés – A műveletet elküldjük a banknak, és ha minden rendben a bank visszaküldi az információt
15
16
void main() { ... InetAddr inet(136, 155, 18, 20); // hozzuk letre a gepet ATM gep(42, "Rokus utca", "OTP", inet); while(true) { gep.run(); } }
ATM gépen futó program 17
class ATM { int id; string place; string bankName; InetAddr bankaddress; // a gep komponensei CardReader *reader; PenzKiado
*penzkiado;
Nyomtato
*nyomtato;
// allapot informacio, milyen allapotban van a gep ATM_STATE allapot; bool on; Session *aktualis; ... 18
ATM id
UML osztálydiagram
place bankName bankaddress reader penzkiado nyomtato allapot on aktualis +ATM +getReader +getNyomtato +getPenzkiado +bekapcsol +kikapcsol +run 19
UML diagramok
20
penzkiado ATM reader
nyomtato
21
Állapot diagram
KIKAPCSOLVA kikapcsol
KISZOLGÁLÁS
bekapcsolás
kártya be / session létrehozás kártya ki / session vége
VÁRAKOZÁS
22
void run() { switch(allapot) { case KIKAPCSOLVA: ... break; case VARAKOZAS: ... break; case KISZOLGALAS: ... break; } } 23
case KIKAPCSOLVA: cout << "OPERATOR: ATM nem elerheto!" << endl; cout << "OPERATOR: Bekapcsoljuk? [i/n]" << endl; cin >> be; if(be == 'i') { int pp; bekapcsol(); // toltsuk fel a gepet penzzel cout << "OPERATOR: Mennyi penzt tegyunk bele? " << endl; cin >> pp; getPenzKiado()->feltolt(pp); allapot = VARAKOZAS; } break;
24
case VARAKOZAS: if(this->getReader()->kartya_olvas() == NULL) { ... // Tegye be a kartyat! cin >> be; if(be == 'i') { cin >> pin; Kartya *k = new Kartya(pin); this->getReader()->kartya_betesz(k); } if(this->getReader()->kartya_olvas()) { aktualis = new Session(this); allapot = KISZOLGALAS; } } break;
25
case KISZOLGALAS: aktualis->kiszolgal(); allapot = VARAKOZAS; break;
26
pénz
penzkiado ATM reader
kartya
nyomtato
session
27
enum SESSION_STATE { KARTYAT_OLVAS, PINT_OLVAS, TRANZAKCIO_VALASZTAS, TRANZAKCIO_VEGREHAJTAS, KARTYA_KIDOB, VEGE }; class Session { private: SESSION_STATE allapot; ATM *atm; public: Session(ATM *a) : atm(a) { allapot = KARTYAT_OLVAS; } void kiszolgal(); };
28
Állapot diagram KÁRTYÁT_OLVAS
sikertelen
sikerült PINT_OLVAS
kilépés
sikerült TRANZAKCIÓT_VÁLASZT újabb tranzakció
vége
választott TRANZAKCIÓT_VÉGREHAJT tranzakció vége KÁRTYÁT_KIDOB
VÉGE 29
void kiszolgal() { while(allapot != VEGE) { switch(allapot) { case KARTYAT_OLVAS: ... break; case PINT_OLVAS: ... break; case TRANZAKCIO_VALASZTAS: ... break; case TRANZAKCIO_VEGREHAJTAS: ... break; case KARTYA_KIDOB: ... break; } } }
30
case KARTYAT_OLVAS: kartya = atm->getReader()->kartya_olvas(); if(kartya != NULL) { allapot = PINT_OLVAS; } else { atm->getNyomtato()->nyomtat("Kartya nem olvashato"); allapot = KARTYA_KIDOB; } break;
31
case PINT_OLVAS: pin=-2; while(pin > 9999 || pin < -1) { atm->getNyomtato()->nyomtat(“Azonosito? (-1 = kilepes):"); cin >> pin; } if(pin == -1) { allapot = KARTYA_KIDOB; } else { allapot = TRANZAKCIO_VALASZTAS; } break; 32
case TRANZAKCIO_VALASZTAS: { int tipus; while(1) { atm->getNyomtato()->nyomtat("Valasszon muveletet: "); ... // menü cin >> tipus; if(tipus < 1 || tipus > 3) atm->getNyomtato()->nyomtat("HIBA: Ervenytelen muvelet"); else break; }
33
switch(tipus) { case 1: t = new Tranzakcio_Kivesz(atm, this, kartya, pin); allapot = TRANZAKCIO_VEGREHAJTAS; break; case 2: t = new Tranzakcio_Info(atm, this, kartya, pin); allapot = TRANZAKCIO_VEGREHAJTAS; break; case 3: allapot = KARTYA_KIDOB; break; } break; } 34
pénz
penzkiado ATM reader
kartya
nyomtato
tranzakcio
session
info
kivesz 35
case TRANZAKCIO_VEGREHAJTAS: { bool ismet; ismet = t->vegrehajt(); delete t; if(ismet) { allapot = TRANZAKCIO_VALASZTAS; } else { allapot = KARTYA_KIDOB; } break; }
36
class Tranzakcio { protected: ATM *atm; Session *session; Kartya *kartya; int pin; static int ser_num; public: Tranzakcio(ATM *a, Session *s, Kartya *k, int p) : atm(a), session(s), kartya(k), pin(p) { ser_num++; } virtual bool vegrehajt() = 0; }; int Tranzakcio::ser_num = 0; 37
class Tranzakcio_Info : public Tranzakcio { public: Tranzakcio_Info(ATM *a, Session *s, Kartya *k, int p) : Tranzakcio(a, s, k, p) {} bool vegrehajt() { Uzenet *u; u = new Uzenet(LEKERDEZES, kartya, pin, ser_num, -1, -1, Penz(-1)); // Ide jon az a kod, amit uzenetet kuld a // banknak a halozaton keresztul Status *ered; ered = OTP.uzenet_kezeles(*u); if(ered->sikeres() == false) { atm->getNyomtato()->nyomtat("HIBA: "); } atm->getNyomtato()->nyomtat(ered->getUzenet()); delete ered; delete u; char c; atm->getNyomtato()->nyomtat("Ismet? [i/n]"); ... } }; 38
class Status { bool siker; string uzenet; public: Status(bool s=false, string u="") : siker(s), uzenet(u) {} bool sikeres() { return siker; } string getUzenet() { return uzenet; } };
39
class Siker : public Status { public: Siker(string u="") : Status(true, u) {} };
class ErvenytelenPIN : public Status { public: ErvenytelenPIN() : Status(false, "Ervenytelen PIN") {} }; ... 40
pénz nyomtato penzkiado ATM
session tranzakcio
reader info
kivesz
kartya siker status uzenet hálózat
szamlak
bank
ervenytelenPIN ervenytelenUzenet
41