„Szoftverarchitektúrák - Jegyzet” változatai közötti eltérés
aNincs szerkesztési összefoglaló |
Nincs szerkesztési összefoglaló |
||
(9 közbenső módosítás, amit 3 másik szerkesztő végzett, nincs mutatva) | |||
1. sor: | 1. sor: | ||
{{Vissza|Szoftverarchitektúrák}} | |||
A régi, doktoranduszok által írt, hivatalos jegyzet [[Media:Szoftarch_jegyzet_2011_patternek.pdf | letölthető innen]]. | |||
Ennél persze több van, érdemes átnézni a tárgyhonlapot. | |||
Tipikus architektúra hibák: | |||
* Scope tévesztése, nem pontos definiálása. | |||
* Stakeholderek pontos azonosítása elmarad. | |||
* Csak funkcionalitásra fókuszálni, UI-t elhanyagolni. | |||
* Leírások (pl. tooltipek) elmaradnak. Ne kelljen gondolkodni a usernek! | |||
* "Forgetting that it needs to be built" | |||
* "Lack of platform precision" | |||
* Skálázhatóság feltételezése hasraütésszerűen. | |||
* DIY Security | |||
* Backup/Recovery plan (katasztrófaterv) hiánya | |||
* Backout plan (visszalépési terv) hiánya | |||
==I. Szolgáltatás-hozzáférési és konfigurációs minták== | ==I. Szolgáltatás-hozzáférési és konfigurációs minták== | ||
===I.1. Wrapper Facade=== | ===I.1. Wrapper Facade=== | ||
Nem OO API-k elé egy OO réteget húzunk, ami nyújt bizonyos szolgáltatásokat, ami felhasználja az alatta levő réteget. Így az alacsony szintű API helyett egy OO-sat hívunk, ez kényelmesebb és hordozhatóbb. Hátránya, hogy a funkcionalitás csökkenhet, valamint valószínűleg lassabb lesz a kód. | Nem OO API-k elé egy OO réteget húzunk, ami nyújt bizonyos szolgáltatásokat, ami felhasználja az alatta levő réteget. Így az alacsony szintű API helyett egy OO-sat hívunk, ez kényelmesebb és hordozhatóbb. Hátránya, hogy a funkcionalitás csökkenhet, valamint valószínűleg lassabb lesz a kód. | ||
===I.2. Component Configurator=== | ===I.2. Component Configurator=== | ||
Egy szolgáltatás interface-re több implementáció is létezhet, amelyek közül nem feltétlenül tudjuk kiválasztani fejlesztés közben a legjobbat. Ezzel a mintával elkészítjük az összes implementációt, és futási időben választjuk ki, hogy melyiket használjuk. A komponenseknek kell az életciklusukat kezelni, tehát elindítani és leállítani. Hátránya, hogy nem determinisztikus, valamint bonyolultabb lesz a kód. | Egy szolgáltatás interface-re több implementáció is létezhet, amelyek közül nem feltétlenül tudjuk kiválasztani fejlesztés közben a legjobbat. Ezzel a mintával elkészítjük az összes implementációt, és futási időben választjuk ki, hogy melyiket használjuk. A komponenseknek kell az életciklusukat kezelni, tehát elindítani és leállítani. Hátránya, hogy nem determinisztikus, valamint bonyolultabb lesz a kód. | ||
16. sor: | 33. sor: | ||
===I.3. Interceptor=== | ===I.3. Interceptor=== | ||
Az interceptor egy olyan eseménykezelő, amit a keretrendszer eseményeire lehet kötni. Hasonlít az AOP-hez. | Az interceptor egy olyan eseménykezelő, amit a keretrendszer eseményeire lehet kötni. Hasonlít az AOP-hez. | ||
28. sor: | 44. sor: | ||
===I.4. Extension Interface=== | ===I.4. Extension Interface=== | ||
Akkor jó, ha úgy kell kiterjeszteni egy osztályt, hogy a kliensen ne kelljen változtatni. Példakódhoz [http://stackoverflow.com/questions/1055833/need-citation-for-extension-interface-pattern-in-java lásd] | |||
Akkor jó, ha úgy kell kiterjeszteni egy osztályt, hogy a kliensen ne kelljen változtatni. Példakódhoz | |||
Szereplői: | Szereplői: | ||
39. sor: | 54. sor: | ||
==II. Eseménykezelési minták== | ==II. Eseménykezelési minták== | ||
===II.1. Reactor=== | ===II.1. Reactor=== | ||
[[OotTervezesiMintak#Reactor | Lásd.]] | |||
Szereplői: | Szereplői: | ||
52. sor: | 65. sor: | ||
===II.2. Proactor=== | ===II.2. Proactor=== | ||
A reactor aszinkron változata, híváskor a kezelőt aszinkron módon hívja meg, és amikor az visszatér, akkor kikeresi a kezelőt, amivel választ tud küldeni. | A reactor aszinkron változata, híváskor a kezelőt aszinkron módon hívja meg, és amikor az visszatér, akkor kikeresi a kezelőt, amivel választ tud küldeni. | ||
===II.3. Asynchronous Completion Token (ACT)=== | ===II.3. Asynchronous Completion Token (ACT)=== | ||
Mint a proactor, csak a választ kezelőt megkapja a feldolgozó, ezért nem kell kikeresni. [http://en.wikipedia.org/wiki/Proactor_pattern Leírás.] | |||
Mint a proactor, csak a választ kezelőt megkapja a feldolgozó, ezért nem kell kikeresni. | |||
===II.4. Acceptor-Connector=== | ===II.4. Acceptor-Connector=== | ||
67. sor: | 78. sor: | ||
==III. Konkurenciakezelési minták== | ==III. Konkurenciakezelési minták== | ||
===III.1. Active Object=== | ===III.1. Active Object=== | ||
[[OotTervezesiMintak#Akt_v_objektum | Lásd.]] | |||
===III.2. Monitor Object=== | ===III.2. Monitor Object=== | ||
[[OotTervezesiMintak#Monitor | Lásd.]] | |||
===III.3. Half-Sync/Half-Async=== | ===III.3. Half-Sync/Half-Async=== | ||
Lényege, hogy hardverfejlesztők aszinkron műveleteket szeretnek, szoftveresek meg szinkronokat. Ezzel a mintával megoldható, hogy mindenki úgy programozzon, ahogy szeretne. | Lényege, hogy hardverfejlesztők aszinkron műveleteket szeretnek, szoftveresek meg szinkronokat. Ezzel a mintával megoldható, hogy mindenki úgy programozzon, ahogy szeretne. | ||
87. sor: | 94. sor: | ||
===III.4. Leader/Followers=== | ===III.4. Leader/Followers=== | ||
[[OotTervezesiMintak#Vezet_k_vet | Lásd.]] | |||
==IV. Szinkronizációs tervezési minták== | ==IV. Szinkronizációs tervezési minták== | ||
===IV.1. Scoped Locking=== | ===IV.1. Scoped Locking=== | ||
Felhasználja, hogy a C++-ban amikor kilép a vezérlés az objektum scope-jából, akkor lefut a destruktora. Így a lock egy Guard osztály, aminek a konstruktorában lefoglalódik a zár, a destruktorában felszabadul. Így a zárolt részt bárhogyan hagyjuk el, biztosan nem marad zárolva. | Felhasználja, hogy a C++-ban amikor kilép a vezérlés az objektum scope-jából, akkor lefut a destruktora. Így a lock egy Guard osztály, aminek a konstruktorában lefoglalódik a zár, a destruktorában felszabadul. Így a zárolt részt bárhogyan hagyjuk el, biztosan nem marad zárolva. | ||
===IV.2. Strategized Locking=== | ===IV.2. Strategized Locking=== | ||
A lényege, hogy a lock objektumot paraméterként megadhatóvá tesszük, így a védett objektum létrehozásakor megadhatjuk, hogy milyen módon zárolható (R/W lock, mutex, stb...). Ehhez kell egy ősosztály, amiből a különböző implementációkat származtatjuk. | A lényege, hogy a lock objektumot paraméterként megadhatóvá tesszük, így a védett objektum létrehozásakor megadhatjuk, hogy milyen módon zárolható (R/W lock, mutex, stb...). Ehhez kell egy ősosztály, amiből a különböző implementációkat származtatjuk. | ||
===IV.3. Thread-Safe Interface=== | ===IV.3. Thread-Safe Interface=== | ||
A probléma az, hogy egy osztályon belüli metódushívásoknál többször is zárolni akar, akkor self-deadlock alakul ki. Ezért elválasztjuk a publikus metódusok hívását és az implementációjukat private metódusokba tesszük, és minden publikus metódus elején zárolunk, a többinél azonban nem. Így ha a függvények egymást hívják, nem lesz újrazárolás, viszont minden bejöbő hívás zárolt lesz. | A probléma az, hogy egy osztályon belüli metódushívásoknál többször is zárolni akar, akkor self-deadlock alakul ki. Ezért elválasztjuk a publikus metódusok hívását és az implementációjukat private metódusokba tesszük, és minden publikus metódus elején zárolunk, a többinél azonban nem. Így ha a függvények egymást hívják, nem lesz újrazárolás, viszont minden bejöbő hívás zárolt lesz. | ||
===IV.4. Double-Checked Locking Optimization=== | ===IV.4. Double-Checked Locking Optimization=== | ||
Ha egy kritikus szakasznak pontosan 1-szer szabad lefutnia, akkor zárolás után is meg kell győződnünk arról, hogy még nem futott-e le. Ez pl. Singletonok létrehozásánál lehet fontos, mivel a létrehozó fv-t több szál is meghívhatja egyszerre, ekkor ha csak záraink vannak, akkor egymás után több példányt is létrehoznak belőle. | Ha egy kritikus szakasznak pontosan 1-szer szabad lefutnia, akkor zárolás után is meg kell győződnünk arról, hogy még nem futott-e le. Ez pl. Singletonok létrehozásánál lehet fontos, mivel a létrehozó fv-t több szál is meghívhatja egyszerre, ekkor ha csak záraink vannak, akkor egymás után több példányt is létrehoznak belőle. | ||
125. sor: | 127. sor: | ||
-- [[SallaiTamas|sashee]] - 2010.10.16. | -- [[SallaiTamas|sashee]] - 2010.10.16. | ||
[[Kategória:Mérnök informatikus MSc]] | |||
[[ |
A lap jelenlegi, 2015. január 18., 23:54-kori változata
A régi, doktoranduszok által írt, hivatalos jegyzet letölthető innen.
Ennél persze több van, érdemes átnézni a tárgyhonlapot.
Tipikus architektúra hibák:
- Scope tévesztése, nem pontos definiálása.
- Stakeholderek pontos azonosítása elmarad.
- Csak funkcionalitásra fókuszálni, UI-t elhanyagolni.
- Leírások (pl. tooltipek) elmaradnak. Ne kelljen gondolkodni a usernek!
- "Forgetting that it needs to be built"
- "Lack of platform precision"
- Skálázhatóság feltételezése hasraütésszerűen.
- DIY Security
- Backup/Recovery plan (katasztrófaterv) hiánya
- Backout plan (visszalépési terv) hiánya
I. Szolgáltatás-hozzáférési és konfigurációs minták
I.1. Wrapper Facade
Nem OO API-k elé egy OO réteget húzunk, ami nyújt bizonyos szolgáltatásokat, ami felhasználja az alatta levő réteget. Így az alacsony szintű API helyett egy OO-sat hívunk, ez kényelmesebb és hordozhatóbb. Hátránya, hogy a funkcionalitás csökkenhet, valamint valószínűleg lassabb lesz a kód.
I.2. Component Configurator
Egy szolgáltatás interface-re több implementáció is létezhet, amelyek közül nem feltétlenül tudjuk kiválasztani fejlesztés közben a legjobbat. Ezzel a mintával elkészítjük az összes implementációt, és futási időben választjuk ki, hogy melyiket használjuk. A komponenseknek kell az életciklusukat kezelni, tehát elindítani és leállítani. Hátránya, hogy nem determinisztikus, valamint bonyolultabb lesz a kód.
Szereplői:
- Komponens: Szolgáltatást leíró interface
- Konkrét komponensek: Az interface-t megvalósító osztályok
- Komponenstár (repository): Tárolja a konkrét komponenseket
- Komponens konfiguráló: A komponensekhez konkrét komponenst rendel, és ezt futásidőben tudja változtatni.
I.3. Interceptor
Az interceptor egy olyan eseménykezelő, amit a keretrendszer eseményeire lehet kötni. Hasonlít az AOP-hez.
Szereplői:
- Konkrét keretrendszer (framework): Egy generikus architektúra
- Elfogó (interceptor): Olyan interface, amely az egyes eseményekre bekövetkező eseménykezelőnek meg kell valósítania
- Konrét elfogó: Interceptor implementációja
- Diszpécser (dispatcher): Eseményekhez van rendelve, ehhez pedig lehet konkrét elfogó. Ez fogja hívni az interceptort.
- Kontextus objektum: Az eseményt és a keretrendszert lehet rajtuk keresztül elérni az elfogóból
- Alkalmazás: A keretrendszeren futó alkalmazás
I.4. Extension Interface
Akkor jó, ha úgy kell kiterjeszteni egy osztályt, hogy a kliensen ne kelljen változtatni. Példakódhoz lásd
Szereplői:
- Komponens: Ezt szeretnénk kiterjeszteni
- Kiterjesztő interface: A komponens szerepeit tartalmazza
- Gyökér interface: Minden komponensnek meg kell valósítania, ettől lehet lekérni a kiterjesztő interface-kat, valamint közös szolgáltatásokat is adhat.
- Kliens: Aki hívja
- Komponensgyár: A gyökeret lehet tőle kikérni
II. Eseménykezelési minták
II.1. Reactor
Szereplői:
- Kezelő: OS biztosítja, ami jelzést tud adni, pl hálózati kapcsolat.
- Szinkron esemény szétválasztó: Addig blokkolódik, amíg nincs jelzés
- Eseménykezelő interface: Megadja, hogyan kell az eseményt feldolgozni
- Konkrét eseménykezelő: Az előző interface-t megvalósítja
- Reaktor interface: Eseménykezelőt lehet hozzáadni és eltávolítani
II.2. Proactor
A reactor aszinkron változata, híváskor a kezelőt aszinkron módon hívja meg, és amikor az visszatér, akkor kikeresi a kezelőt, amivel választ tud küldeni.
II.3. Asynchronous Completion Token (ACT)
Mint a proactor, csak a választ kezelőt megkapja a feldolgozó, ezért nem kell kikeresni. Leírás.
II.4. Acceptor-Connector
- Acceptor: Passzívan várakozik bejövő kapcsolatra
- Connector: Aktívan felép egy kapcsolatot
A kapcsolat felépítése után várakoznak eseményre, amit valamelyik másik minta fog kezelni. Azért jó, mert leválasztható vele az, hogy éppen klienst vagy szervert írunk.
III. Konkurenciakezelési minták
III.1. Active Object
III.2. Monitor Object
III.3. Half-Sync/Half-Async
Lényege, hogy hardverfejlesztők aszinkron műveleteket szeretnek, szoftveresek meg szinkronokat. Ezzel a mintával megoldható, hogy mindenki úgy programozzon, ahogy szeretne.
Szereplői:
- Aszinkron réteg: Az aszinkron hívások végrehajtásáért felel
- Szinkron réteg: A szinkron hívások végrehajtásáért felel
- Üzenetkezelő réteg: A másik 2 réteg üzenetekkel kommunikál egymással, ezen keresztül
- Eseményfigyelő: Eseményre meghívja az aszinkron réteget
III.4. Leader/Followers
IV. Szinkronizációs tervezési minták
IV.1. Scoped Locking
Felhasználja, hogy a C++-ban amikor kilép a vezérlés az objektum scope-jából, akkor lefut a destruktora. Így a lock egy Guard osztály, aminek a konstruktorában lefoglalódik a zár, a destruktorában felszabadul. Így a zárolt részt bárhogyan hagyjuk el, biztosan nem marad zárolva.
IV.2. Strategized Locking
A lényege, hogy a lock objektumot paraméterként megadhatóvá tesszük, így a védett objektum létrehozásakor megadhatjuk, hogy milyen módon zárolható (R/W lock, mutex, stb...). Ehhez kell egy ősosztály, amiből a különböző implementációkat származtatjuk.
IV.3. Thread-Safe Interface
A probléma az, hogy egy osztályon belüli metódushívásoknál többször is zárolni akar, akkor self-deadlock alakul ki. Ezért elválasztjuk a publikus metódusok hívását és az implementációjukat private metódusokba tesszük, és minden publikus metódus elején zárolunk, a többinél azonban nem. Így ha a függvények egymást hívják, nem lesz újrazárolás, viszont minden bejöbő hívás zárolt lesz.
IV.4. Double-Checked Locking Optimization
Ha egy kritikus szakasznak pontosan 1-szer szabad lefutnia, akkor zárolás után is meg kell győződnünk arról, hogy még nem futott-e le. Ez pl. Singletonok létrehozásánál lehet fontos, mivel a létrehozó fv-t több szál is meghívhatja egyszerre, ekkor ha csak záraink vannak, akkor egymás után több példányt is létrehoznak belőle.
Pl:
static SingletonClass *GetInstance() { //Az első ellenőrzés. if (instance == 0) { //Szinkronizálás. Guard guard(lock); //A második ellenőrzés. if (instance == 0) instance = new SingletonClass(); } return instance; } }