Aspektusorientált programozásA számítástechnikában az aspektusorientált programozás (AOP) egy olyan programozási paradigma, amelynek célja a modularitás növelése azáltal, hogy lehetővé teszi a kereszthivatkozások szeparálását (SoC). Ez úgy történik, hogy kiegészítő viselkedést ad a meglévő kódhoz (advice), önmagában a kód módosítása nélkül, ehelyett külön megjelöli, hogy melyik kódot módosítják egy „pointcut” specifikációval, például „naplózza az összes függvényhívást, amikor a függvény neve »set«-tel kezdődik”. Ez lehetővé teszi az üzleti logika szempontjából a nem központi viselkedés (például naplózás) hozzáadását a programhoz a funkcionalitás alapját képező kód túlzsúfolása nélkül. Az AOP alapja az aspektusorientált szoftverfejlesztésnek. Az AOP programozási módszereket és eszközöket tartalmaz, amelyek támogatják a vonatkozások modulációját a forráskód szintjén, míg az "aspektusorientált szoftverfejlesztés" egy teljes mérnöki tudományágat jelent. Az aspektusorientált programozás magában foglalja a program logikájának különálló részekre bontását (úgynevezett vonatkozások, koherens funkcionális területek). Szinte az összes programozási paradigma támogatja a vonatkozások bizonyos szintű csoportosítását és beágyazását különálló, független entitásokba absztrakciók (például függvények, eljárások, modulok, osztályok, metódusok) biztosításával, amelyek felhasználhatók ezeknek a vonatkozásoknak az implementálására, absztrakciójára és összeállítására. Néhány vonatkozás „átvág” számos absztrakción egy programon belül, és meghiúsítja a végrehajtás ezen formáit. Ezeket a vonatkozásokat cross-cutting (keresztülvágó) vagy horizontális vonatkozásoknak (vagy szimplán kereszthivatkozás) nevezik. A naplózás egy kereszthivatkozási problémát szemléltet, mivel a naplózási stratégia szükségszerűen érinti a rendszer minden naplózott részét. A naplózás ezzel keresztezi az összes naplózott osztályt és metódust. Minden AOP implementációnak vannak olyan átfogó kifejezései, amelyek mindegyik vonatkozást egységbe zárják. Az implementációk közötti különbség a biztosított konstrukciók erejében, biztonságában és használhatóságában rejlik. Például az olyan megszakítók, amelyek meghatározzák a keresztmetszet korlátozott formájának kifejezésére szolgáló metódusokat, a típusbiztonság vagy a hibakeresés támogatása nélkül. Az AspectJ-nek számos ilyen kifejezése van, melyeket beilleszthet egy speciális osztályba, egy aspektusba. Például egy aspektus megváltoztathatja az alapkód viselkedését (a program nem aspektusú részét), ha tanácsot (kiegészítő viselkedést) alkalmaz a különféle csatlakozási pontokban (a program pontjai), amelyeket egy mennyiségi meghatározás, vagy lekérdezés határoz meg, melyet pointcutnak nevezünk (amely észleli, hogy egy adott csatlakozási pont megegyezik-e). Egy aspektus binárisan kompatibilis szerkezeti változtatásokat is végrehajthat más osztályokban, például tagok vagy szülők hozzáadásával. TörténeteAz AOP-nak számos közvetlen előzménye van, A1 és A2: reflexiós és metaobjektum protokollok, tárgyorientált programozás, Kompozíciós Szűrők és Adaptív Programozás.[1] Gregor Kiczales és a Xerox PARC kollégái kifejlesztették az AOP kifejezett fogalmát, majd ezt követték az AspectJ AOP Java kiterjesztésével. Az IBM kutatócsoportja egy eszközi megközelítést alkalmazott a nyelvi tervezési megközelítés felett, és 2001-ben javaslatot tett a Hyper/J és a Concern Manipulation Environment környezetre, amelyek még nem voltak széles körben elterjedtek. A cikk példái az AspectJ-t használják. A Microsoft Transaction Server kiszolgálót tekintik az AOP első nagyobb alkalmazásának, amelyet az Enterprise JavaBeans követett.[2][3] Motiváció és alapkoncepciókÁltalában egy aspektus szét van szórva vagy összekeveredve, ami megnehezíti a kód kezelhetőségét és megértését. Ez abban valósul meg, hogy egy függvényt (például naplózás), több független függvény használhat, teljesen független rendszerekben, különböző forrásnyelvekben. Ez azt jelenti, hogy a naplózás megváltoztatásához szükség lehet az összes érintett modul módosítására. Ezek a szempontok nem csak azon a rendszereknek a fő funkciójában keveredhetnek össze, amelyekben kifejeződnek, hanem akár egymással is. Ezért, az egyik kereszthivatkozás megváltoztatása hatással lehet a többi funkcióra. Például, vegyünk egy banki alkalmazást, egy nagyon egyszerű koncepcióval, ami az egyik számláról a másikra utal összeget:[4] void transfer(Account fromAcc, Account toAcc, int amount) throws Exception {
if (fromAcc.getBalance() < amount)
throw new InsufficientFundsException();
fromAcc.withdraw(amount);
toAcc.deposit(amount);
}
Ez az átviteli módszer azonban figyelmen kívül hagyja azokat a bizonyos szempontokat, amelyeket egy telepített alkalmazás igényelne: hiányzik a biztonsági ellenőrzés, annak ellenőrzésére, hogy a jelenlegi felhasználó rendelkezik-e engedéllyel e művelet végrehajtásához; egy adatbázis-tranzakciónak be kell építenie a műveletet a véletlen adatvesztés elkerülése érdekében; a diagnosztika érdekében a műveletet be kell jegyezni a rendszernaplóba. A példa kedvéért egy verzió, amely ezeket az új vonatkozásokat implementálja így nézhet ki: void transfer(Account fromAcc, Account toAcc, int amount, User user,
Logger logger, Database database) throws Exception {
logger.info("Transferring money...");
if (!isUserAuthorised(user, fromAcc)) {
logger.info("User has no permission.");
throw new UnauthorisedUserException();
}
if (fromAcc.getBalance() < amount) {
logger.info("Insufficient funds.");
throw new InsufficientFundsException();
}
fromAcc.withdraw(amount);
toAcc.deposit(amount);
database.commitChanges(); // Atomic operation.
logger.info("Transaction successful.");
}
Ebben a példában egyéb érdekek keveredtek össze az alapvető funkcionalitással (néha üzleti logikai vonatkozásnak nevezik). A tranzakciók, a biztonság és a naplózás mind a kereszthivatkozásokat szemléltetik. Most fontoljuk meg, mi történik, ha hirtelen meg kell változtatnunk (például) az alkalmazás biztonsági szempontjait. A program aktuális verziójában a biztonsággal kapcsolatos műveletek több metóduson keresztül lettek létrehozva, egy ilyen változtatás komoly erőfeszítéseket igényelne. Az AOP megpróbálja ezt a problémát megoldani azáltal, hogy lehetővé teszi a programozónak, hogy kifejezze ezeket a kereszthivatkozásokat önálló modulokban, úgynevezett aspektusokban (szempontokban). A szempontok tartalmazhatnak adviceokat (a program meghatározott pontjaihoz csatolt kódot) és típusközi deklarációkat (strukturális tagok hozzáadva más osztályokhoz). A biztonsági modul például tartalmazhat olyan adviceokat, amelyek biztonsági ellenőrzést hajtanak végre a bankszámla elérése előtt. A pointcut meghatározza azokat az időpontokat (csatlakozási pontok), amikor egy bankszámlához hozzáférhetünk, és az advice törzsében szereplő kód határozza meg a biztonsági ellenőrzés végrehajtásának implementációját. Így mind az ellenőrzés, mind a területek egy részen kezelhetők. Ezenkívül egy jó pointcut előrejelzi a program későbbi változásait, tehát ha egy másik fejlesztő új metódust hoz létre a bankszámla eléréséhez, az advice az új módszerre vonatkozik annak végrehajtásakor. A fentebb említettek példájára egy naplózás megvalósítása egy aspektusban: aspect Logger {
void Bank.transfer(Account fromAcc, Account toAcc, int amount, User user, Logger logger) {
logger.info("Transferring money...");
}
void Bank.getMoneyBack(User user, int transactionId, Logger logger) {
logger.info("User requested money back.");
}
// Other crosscutting code.
}
Az AOP kapcsán gondolhatunk egy hibakeresési eszközre, vagy akár egy felhasználói szintű kellékre. Az advicet tartalékolhatjuk azokra az esetekre, amikor nem sikerül egy funkciót megváltoztatni (felhasználói szint),[5] vagy pedig nem akarjuk megváltoztatni a függvényt az élesen futó alkalmazásban (hibakezelés) Csatlakozási pontok modelljeAz aspektusorientált nyelv tanáccsal kapcsolatos komponense meghatározza a csatlakozási pontot (JPM). A JPM három dolgot határoz meg:
A csatlakozási pont modellek összehasonlíthatók meghatározásaik, valamint ezekben a pontokban engedélyezett műveleteik és a kifejezhető szerkezeti fejlesztéseik, és a kitett csatlakozási pontjaik alapján. Az AspectJ csatlakozási pont modellje
Egyéb potenciális csatlakozási pont modellekMás típusú JPM is létezik. Az összes advice nyelv meghatározható a JPM alapján. Például az UML feltételezett nyelvén a következő JPM lehet:
Típusközi deklarációkA típusközi deklarációk lehetőséget adnak a modulok felépítését érintő kereszthivatkozások kifejezésére. Ezek más néven nyílt osztályok és kiterjesztési metódusok, amelyek lehetővé teszik a programozók számára, hogy egy helyen deklarálják egy másik osztály tagjait vagy szüleit, általában azért, hogy egy problémára vonatkozó kód egészét egy aspektusben összevonják. Például, ha egy programozó a visitor felhasználásával valósította meg a megjelenítés-frissítést, egy visitor (látogató) mintát használó típusú típusközi deklaráció az AspectJ-ben így nézhet ki: aspect DisplayUpdate {
void Point.acceptVisitor(Visitor v) {
v.visit(this);
}
// other crosscutting code...
}
Ez a kódrészlet hozzáadja az Fontos követelmény, hogy minden strukturális kiegészítés kompatibilis legyen az eredeti osztállyal, hogy a meglévő osztály kliensei továbbra is működjenek, kivéve, ha az AOP megvalósítás azt várja el, hogy minden klienst folyamatosan ellenőrízzen. ImplementációAz AOP programok kétféleképpen befolyásolhatják a többi programot, az alapul szolgáló nyelvektől és a környezettől függően:
A környezetek megváltoztatásának nehézsége azt jelenti, hogy a legtöbb megvalósítás kompatibilis kombinációs programokat hoz létre „szövésnek” (weaving) nevezett folyamat révén – a program átalakításának különös esete. Egy aspektus szövő leolvassa az aspektusorientált kódot, és megfelelő objektumorientált kódot generál integrált szempontokkal belőle. Ugyanaz az AOP nyelv különféle szövésmódszerekkel implementálható, így a nyelv szemantikája soha meg nem érthető a szövés implementálásának szempontjából. Csak a megvalósítás sebességét és a telepítés könnyebbségét befolyásolja az, hogy milyen kombinációs módszert alkalmaznak. A rendszerek forrásszintű szövést hajtanak végre olyan előprocesszorok segítségével (mivel a C++ eredetileg a CFront programban került megvalósításra), amelyek megkövetelik a hozzáférést a program forrásfájljaihoz. A Java jól definiált bináris formája azonban lehetővé teszi a bytekód szövők számára, hogy bármilyen Java programmal együtt működjenek .class fájl formátumban. A bytekód szövők telepíthetők (deploy) az építés (build) során, vagy ha a szövési modell osztályonkénti, akkor az osztálybetöltés során. Az AspectJ 2001-ben forrásszintű szövést kezdett kialakítani, majd 2002-ben egy osztályonkénti bytekód szövőt hozott létre, és fejlett terhelési idő támogatást nyújtott az AspectWerkz 2005-ös integrációja után. Bármely megoldásnak, amely egyesíti a programokat futásidő alatt, olyan aspektusokat kell tartalmaznia, amelyek megfelelően elkülönítik őket, hogy fenntartsák a programozó szegregált modelljét. A Java bytekód támogatása több forrásfájlnál lehetővé teszi a hibakeresők számára, hogy egy megfelelően szőtt .class fájlon átlépjenek a forrásszerkesztőben. Néhány harmadik féltől származó kódvisszafejtő program (decompiler) nem tudja feldolgozni a szőtt kódot, mert Javac által előállított kódot várnak, az összes támogatott bytekód forma helyett. Az üzembe helyezési időszövés (deploy-time weaving) egy másik megközelítést kínál.[6] Ez alapvetően utófeldolgozást von maga után, de a létrehozott kód javítása helyett ez a szövés megközelítés alosztályozza a meglévő osztályokat úgy, hogy a módosításokat metódus felülírással (method overriding) vezeti be. A meglévő osztályok változatlanok maradnak, még futásidejűleg is, és az összes létező eszköz (hibakeresők, profilkészítők stb.) felhasználható a fejlesztés során. Hasonló megközelítés már bebizonyosodott számos Java EE alkalmazáskiszolgáló – például az IBM WebSphere – implementálásában. TerminológiaAz aspektusorientált programozásban használt alap terminológia a következőket foglalja magában:
Összehasonlítás más programozási paradigmákkalA aspektusok az objektumorientált programozás és a számítási reflexiók során merültek fel. Az AOP nyelvek funkciója hasonló, de korlátozóbb, mint a metaobjektum protokollok. Az aspektusok szorosan kapcsolódnak a programozási koncepciókhoz, például az objektumokhoz, a mixinekhez és a delegáláshoz (delegation). Az aspektusorientált programozási paradigmák felhasználásának további módjai a Kompozíciószűrő és a hyperslice megközelítés. Már az 1970-es évek óta a fejlesztők olyan lehallgatási és küldési javításokat használnak, amelyek hasonlítanak az AOP megvalósítás metódusaira, ám ezeknek a szemantikáknak soha nem volt olyan része, amelyeket a keresztmetszeti (crosscutting) leírások biztosítanak. A tervezők fontolóra vették a kód szeparálásának alternatív lehetőségeit, például a C# részleges típusait, de az ilyen megközelítésekben nincs olyan számszerűsítő mechanizmus, amely lehetővé teszi a kód több csatlakozási pontjának elérését egyetlen deklaratív kijelentéssel (statement). Bár úgy tűnhet, hogy független, a tesztelés során a mock vagy metódus részlet (method stub) használata AOP technikák alkalmazását igényli, például az advice környékén és így tovább. Az együttmûködõ objektumok itt a teszt céljából kereszthivatkozássá válnak. Így a különféle mock objektum keretrendszerek biztosítják ezeket a funkciókat. Például egy folyamat meghív egy szolgáltatást, hogy megkapja az egyenlegösszeget. A folyamat tesztelésekor, az összeg származása, nem fontos, csak az, hogy a folyamat a követelményeknek megfelelően használja az egyenleget. Az örökléssel kapcsolatos kérdésekA programozóknak el kell tudniuk olvasni a kódot, és meg kell érteniük, hogy mi történik a hibák elkerülése érdekében.[9] Még megfelelő oktatás mellett is nehézkes lehet a kereszthivatkozások megértése a program statikus felépítésének és dinamikus folyamatának vizualizálásával kapcsoltban nyújtott megfelelő támogatás nélkül.[10] 2002-től kezdve az AspectJ IDE-bővítményeket kezdett biztosítani a kereszthivatkozások vizualizálásának támogatására. Ezek a szolgáltatások, valamint az aspektus kód segéd és a refaktorálás manapság elterjedtek. Tekintettel az AOP erejére, ha egy programozó logikai hibát követ el a kereszthivatkozás kifejezésében, az széles körű programhibához vezethet. Ezzel szemben egy másik programozó megváltoztathatja a program csatlakozási pontjait – például átnevezéssel vagy metódusok áthelyezésével – oly módon, amit az aspektus író nem várt előre. A kereszthivatkozás modularizálásának egyik előnye, hogy lehetővé teszi egy programozó számára azt, hogy könnyen befolyásolja az egész rendszert; Ennek eredményeként az ilyen problémák konfliktusként jelennek meg két vagy több fejlesztő közötti felelősségként egy adott hiba miatt. E problémák megoldása azonban sokkal könnyebb lehet AOP jelenlétében, mivel csak az aspektust kell megváltoztatni, míg a problémák AOP nélkül sokkal elterjedőbbek lehetnek a programon belül. KritikaAz AOP hatásának legalapvetőbb kritikája az, hogy az irányítás áramlás (control flow) el van takarva, és hogy ez nem csak rosszabb, mint a sok rosszindulatú GOTO, hanem valójában szorosan analóg a COME FROM kijelentés viccével.[10] Az alkalmazás elhanyagoltsága, amely alapvető fontosságú az AOP sok meghatározása szempontjából (a kérdéses kódnak nincs utalása arra, hogy egy advicet alkalmazni fognak, ehelyett a pointcutban pontosítanak), azt jelenti, hogy az advice nem látható, ellentétben egy explicit metódus hívással.[10][11] Például hasonlítsa össze a COME FROM programot:[10] 5 INPUT X
10 PRINT 'Result is :'
15 PRINT X
20 COME FROM 10
25 X = X * X
30 RETURN
Analóg szemantikai AOP töredékkel (fragment): main() {
input x
print(result(x))
}
input result(int x) { return x }
around(int x): call(result(int)) && args(x) {
int temp = proceed(x)
return temp * temp
}
Valójában a pointcut függhet a futásidejű körülményektől, és így nem lehet statikusan determinisztikus. Ezt enyhíteni lehet, de nem lehet megoldani statikus elemzéssel és IDE támogatással, amely megmutatja, hogy mely tanácsok egyeznek meg potenciálisan. Általános kritika az, hogy az AOP célja "mind a modularitás, mind a kód szerkezetének" javítása, ám néhányan azt állítják, hogy ehelyett aláássák ezeket a célokat, és akadályozzák a "programok független fejlesztését és érthetőségét".[12] Pontosabban, a pointcut általi számszerűsítés megszakítja a modularitást: "általában egy teljes program ismeretével kell rendelkezni egy aspektus orientált program dinamikus végrehajtásának megvitatására."[13] Továbbá, bár céljait (a kereszthivatkozások modularizálását) jól értik, a tényleges definíciója nem egyértelmű, és nem különböztethető meg egyértelműen a többi jól bevált technikától.[12] A kereszthivatkozások potenciálisan keresztül vágják egymást, és valamilyen felbontási mechanizmust igényelnek, mint például az elrendezés.[12] Valójában az aspektusok magukra is alkalmazhatók, és olyan problémákhoz vezethetnek, mint például a hazug paradoxona.[14] A technikai kritika magában foglalja azt, hogy a pointcutok mennyiségi meghatározása (amely meghatározza az adviceok végrehajtásának helyét) "rendkívül érzékeny a program változásaira", amelyet törékeny pointcut problémaként ismernek.[12] A pointcuttal kapcsolatos problémák megoldhatatlanok: ha a pointcutok számszerűsítését explicit kommentárokkal helyettesítjük, akkor inkább egy attribútumorientált programozást kapunk, amely egyszerűen egy explicit szubrutin hívás, és ugyanolyan szétszórási problémától szenved, amely megoldására az AOP-t tervezték.[12] ImplementációkA következő programozási nyelvek valósították meg az AOP-t, a nyelven belül vagy külső könyvtárként.
További linkek
Megjegyzések és hivatkozások
További irodalom
FordításEz a szócikk részben vagy egészben az Aspect-oriented programming című angol Wikipédia-szócikk ezen változatának fordításán alapul. Az eredeti cikk szerkesztőit annak laptörténete sorolja fel. Ez a jelzés csupán a megfogalmazás eredetét és a szerzői jogokat jelzi, nem szolgál a cikkben szereplő információk forrásmegjelöléseként. Külső linkek
|
Portal di Ensiklopedia Dunia