Szoftverarchitektúrák - Jegyzet

A VIK Wikiből


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

Lásd.

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

Lásd.

III.2. Monitor Object

Lásd.

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

Lásd.

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;
}
}

-- Velias - 2010.10.14. -- sashee - 2010.10.16.