Aspektově orientované programování
Z Wikipedie, otevřené encyklopedie
V softwarovém inženýrství, se paradigma aspektově orientovaného programování (AOP, anglicky Aspect-oriented Programming) pokouší pomoct programátorovi v oddělení koncernů, neboli rozbít program na jasné části, které co nejméně překrývají různou funkcionalitu. Zajdeme-li do důsledků, AOP se zaměřuje na modularizaci a zapouzdření průřezových koncernů.
Původcem tohoto konceptu je Gregor Kiczales a jeho tým v Xerox PARC. Tento tým také vyvinul první, a stále nejpopulárnější, aspektově orientovaný jazyk: AspectJ.
Starší programovací metodologie, včetně procedurálního programování a objektově orientovaného programování, se podobně zaměřují na oddělení a zapouzdření koncernů (nebo jiných zájmových oblastí) do samostatných entit. Například procedury, balíky, třídy a metody pomáhají programátorům zapouzdřit koncerny do samostatných entit. Ale ačkoli všechny tyto metodologie dokážou zdárně zapouzdřit mnoho softwarových koncernů, některé koncerny se vzpírají tak snadnému zapouzdření. Softwaroví inženýři tomu říkají průřezové koncerny (crosscutting concerns), protože existují ve více částech programu.
Logování poskytuje vzorový příklad průřezového koncernu, protože logovací strategie se nutně dotýká každé jedné logované části systému. Logování tudíž prořezává všechny logované třídy, metody i procedury.
Typicky, implementace v AOP jazyku hledá jak zapouzdřit tyto typy průřezové koncerny představením nového konstruktu zvaného aspekt. Aspekt může pozměnit chování základního kódu (neaspektové části programu) aplikováním advice (dodatečného chování) na stanovené přípojné body (body ve struktuře provádění programu), zvaný pointcut (logický popis sady bodů průniku).
Provedení metody nebo předání vlastnosti je slouží za vzor bodů průniku v mnoha AOP jazycích. Pointcut může sestávat například ze všech referencí na určitou sadu vlastností.
Obsah |
[editovat] Motivace a základní koncepty
Jádrem aspektově orientovaného programování je umožnění lepšího oddělení koncernů, dovolením programátorovi vytvářet průřezové koncerny jako prvotřídní programové moduly. (Průřezové koncerny programu, definované jako tyto části (neboli aspekty), při standardních mechanizmech návrhu končívají rozptýlením přes rozmanité programové moduly a zašmodrcháním s ostatními moduly.)
Představme si kupříkladu bankovní aplikaci s koncepčně velmi jednoduchou metodou pro převod částky z jednoho účtu na jiný:
void transfer(Account fromAccount, Account toAccount, int amount) { if (fromAccount.getBalance() < amount) { throw new InsufficientFundsException(); } fromAccount.withdraw(amount); toAccount.deposit(amount); }
Pro zdrojáky je použitá Java-like syntaxe, protože v současnosti se většina dějství kolem AOP tak nějak motá kolem Javy a příbuzných jazyků.
Nicméně, v bankovních aplikacích reálného světa se tato metoda pro přenos zdá daleko od adekvátnosti. Musíme vložit bezpečnostní kontroly pro ověření, že aktuální uživatel je autorizován k provedení této operace. Musíme uzavřít operaci do databázové transakce abychom se vyhli nekonzistenci dat. Musíme operaci zaznamenat v systémovém logu kvůli berňáku. A tak dál. Velmi zjednodušená verze se všemi těmito novými koncerny může vypadat nějak takhle:
void transfer(Account fromAccount, Account toAccount, int amount) { if (!getCurrentUser().canPerform(OP_TRANSFER)) { throw new SecurityException(); } if (amount < 0) { throw new NegativeTransferException(); } if (fromAccount.getBalance() < amount) { throw new InsufficientFundsException(); } Transaction tx = database.newTransaction(); try { fromAccount.withdraw(amount); toAcount.deposit(amount); tx.commit(); systemLog.logOperation(OP_TRANSFER, fromAccount, toAccount, amount); } catch(Exception e) { tx.rollback(); } }
Kód rychle ztratil svou eleganci a jednoduchost, protože různé nové koncerny byly zašmodrchány se základní funkcionalitou (někdy zvanou koncern obchodní logiky). Transakce, zabezpečení, logování atd. znázorňují průřezové koncerny.
Také si představte, co se stane, když najednou potřebujeme změnit (např.) bezpečnostní schémata té aplikace. V současné verzi programu jsou operace související se zabezpečením zašmodrchány přes množství metod, a tak by změna vyžadovala značné úsilí.
Takže, objevili jsme, že na rozdíl od základních koncernů systému, průřezové koncerny nejsou řádně zapouzdřeny ve svých vlastních modulech. To navyšuje složitost systému a činí údržbu značně složitější.
AOP se pokouší tento problém vyřešit tím, že umožní programátorovi vyvinout průřezové koncerny jako plné samostatné moduly zvané aspekty. Ve většině AOP jazycích, aspekt zahrnuje jeden nebo více kusů advice (kousky kódu - jako metody) a seznam přípojných bodů (body v hlavním programu, na které advice mají být propleteny). Například bezpečnostní modul může obsahovat advice, které vykoná bezpečnostní ověření s instrukcemi pro propletení tohoto kousku kódu do začátku metod a(), b() a c() nějaké třídy. Mocné mechanizmy umožňují obsáhlé specifikace přípojných bodů, takže vývojáři nemusejí označovat místa pro připletení ručně. Tyto mechanizmy jsou obecně známé jako jazyky pro specifikaci pointcutů (pointcut specification languages).
[editovat] Modely přípojných bodů (JPM)
Způsob, jakým aspekty interaktují spolu se základním programem je v zásadě definován modelem přípojného bodu (JPM - zkratka z Join Point Model), ve které je aspekt napsán. JPM definuje tři věci:
- Kde se aspekt aplikuje. Toto je často nazýváno přípojné body.
- Způsob, jakým specifikovat (nebo kvantifikovat) rozmanité přípojné body. Tyto jsou často nazývány pointcuty. Poincut je dotaz přes všechny přípojné body programu, který z nich vybere malou podsadu.
- Prostředky ovlivnění chování na přípojných bodech. V aspektu je toto často nazývané advice.
AspectJ má dva JPM: pointcuty s advicy a mezitypové deklarace. Ostatní aspektové jazyky mají odlišné JPM.
[editovat] Pointcuty a advice JPM v AspectJ
- Přípojné body v tomto JPM jsou dobře definované body přes výkon programu. To může obsahovat: vykonání metody, instantování objektu nebo vyhození výjimky. Za povšimnutí stojí, že tyto přípojné body jsou čistě dynamické a můžou se objevit za běhu. Tudíž, pointcuty a advice JPM v AspectJ je známé jako model dynamických přípojných bodů.
- Pointcuty jsou specifikovány dotazem přes program. Jeden takový pointcut vypadá takto:
pointcut set() : execution(* *.set*(..) ) && this(Point);
- Tento pointcut specifikuje všechny přípojné body korespondující s vykonáním kterékoli metody začínající na
set
, pokud vykonávající objekt je typuPoint
.
- Advice je specifikováno způsobem podobným metodě. Přesto advice není nikdy přímo voláno. Je voláno pouze když připojený pointcut je vyhodnocen kladně. Tady je příklad:
after() : set() {
Display.update();
}
To říká že po (after) kladném vyhodnocení set() pointcutu se vykoná příkazy specifikované v těle toho advice.
[editovat] Mezitypové deklarace v AspectJ
Druhé JPM v AspectJ je známé jako mezitypové deklarace (inter-type declarations). To je mechanizmus, který umožňuje aspektu přidat deklarace navíc k existující třídě nebo objektu. Tento koncept je známý jako „otevřené třídy“. Mezitypová deklarace vypadá třeba takhle:
aspect VisitAspect {
Point.acceptVisitor(Visitor v) {
v.visit(this);
}
}
Tento kousek kódu přidá metodu
acceptVisitor
do třídyPoint
.
- Přípojné body jsou všechny neanonymní typy v programu.
- Pointcuty jsou názvy tříd nebo rozhranní.
- Prostředky ovlivnění změn v pointcutech jsou přidáním deklarací do typu.
[editovat] Ostatní modely přípojných bodů
Jsou i další JPM. Všechny aspektové jazyky můžou být definovány v náležitostech jejich JPM. Například hypotetický aspektový jazyk pro UML může mít následující JPM:
- Přípejné body jsou prvky modelu.
- Pointcuty jsou některé boolovské výrazy kombinující prvky modelu.
- Prostředky ovlivnění na těchto bodech jsou vizualizace všech vyhovujících přípojných bodů.
[editovat] Proplétání
Proplétání (angl. Weaving) - vkládání advice prezentovaného v aspektu do specifikovaných přípojných bodů přidružených k advice - poskytuje konečný úkon kteréhokoli AOP řešení.
V původním představení AOP, Kiczales a jeho tým vyjmenoval následující možnosti prolétání:
- Předzpracování zdroje (prostě preprocessor, podobný prvním implementacím C++).
- Předzpracování binárních souborů (post-processor).
- AOP znalý překladač.
- Proplétání během zavádění (např v případě Javy, proplétání relevantních advice při každém načtení třídy do JVM).
- Proplétání za běhu (sledovat každý přípojný bod za běhu a vykonat všechny relevantní advice).
První dvě volby komplikují vývojový proces, zatímco poslední dvě volby můžou zpomalit výkon programu. Poslední volby (proplétání za běhu) navíc vyžaduje zvláštní aspektů znalé výkonné prostředí. Ve světě Javy to znamená zvláštní JVM.
AspectJ v současnosti používá řešení přes jednoúčelový překladač. Překladač generuje standardní class soubory (Java byte-code), kterým kterákoli standardní JVM tedy rozumí. Proplétání při zavádění bude přidáno v následujícím vydání jako výsledek spojení AspectJ a AspectWerkz.
Všechna vyjmenovaná řešení (kromě posledního) předpokládají změnu kódu na některém místě; kód generovaný pro danou Java třídu překladačem (po zpracování a/nebo zavádění) neodpovídají tomu, co by generoval standardní Java překladač, takže nyní obsahují připletené části advice kódu. Leckdo toto vidí jako hlavní slabou stránku AOP, protože to komplikuje obojí - programátorovo pochopení modelu vykonání programu a použití jakéhokoli standardního, existujícího, nástroje, jako debuggery.
Cohen a Gil vytvořili novou alternativu: představují pojem proplétání během rozvinutí (deploy-time weaving). To v základě znamená post-processing, ale místo úpravy generovaného kódu navrhují subclassing existujících tříd, takže úpravy představují předefinování metod. Existující třídy zůstávají nedotčené, dokonce i za běhu a všechny existující nástroje (debuggery, profiléry apod.) můžou být klidně při vývoji použity. Podobný přístup sám o sobě byl už představen v implementaci mnoha J2EE aplikačních serverů, jako IBM WebSphere.
[editovat] AOP a ostatní programovací paradigmata
Aspekty se vynořily z objektově orientovaného programování a nabízí podobnou funkcionalitu jako meta-object protocol. Aspekty úzce souvisejí s programovacími koncepty jako subjekty, mixin a delegace. Další způsoby užití aspektově orientovaných programovacích paradigmat zahrnuje Composition Filters a hyperslices approach.
Matematicky, aspekty formují druhořádové rozšíření kteréhokoli programovacího paradigmatu: zatímco obvyklá programovací paradigmata dovolují úvahu o samostatných funkcích, zprávách a tak dál pomocí signatury funkce/zprávy, AOP umožňuje úvahu o celých sadách těchto entit užitím pointcutů s divokými znaky (wildcards) v jejich signatuře. Takto může jeden vidět AOP jako mocné, logické, rozšíření, spíše než jako nezávislé paradigma. Třeba Fiedrich Steimann takový pohled zastával.
Ale zastánci AOP to prosazují jako externí balík dopravitelný spolu s nějakou aplikací. Například, pokud program samotný nemá podporu pro zabezpečení, AOP balík může poskytnout modulární rozšíření aplikace, nabízející zabezpečení.
[editovat] Problémy pro AOP
Debugování se může stát jedním z největších problémů pro AOP. Zatímco na syntaktické úrovni jsou AOP kódy programu odděleny, na běhové úrovni nikoli. Proplétání koncernů se může stát nepředvídatelné pokud není určeno, který aspekt by měl převládat. Návrháři už vzali v potaz alternativní způsoby oddělení kódu, jako částečné typy v C#. Nicméně, takové postupy ztrácí bezpočet mechanizmů umožňujících programátorům dosáhnout několika přípojných bodů s jedním deklarativním statementem.
Jiný problém pro AOP je neúmyslné označení přípojných bodů přes divoké znaky. Programátor, který vytvoří novou metodu, může bezděčně vybrat název, který bude některé advice nechtěně aplikovat. Podobně přejmenování metody může kompletně změnit svou sémantiku. Musí všichni programátoři, kteří mění základní kód, nastudovat obsáhlou sadu jmenných konvencí specifických pro daný projekt, aby se vyhnuli takovýmto složitostem? Vývojová prostředí s AOP můžou zviditelnit vhodnost použití advice, ale je otevřenou otázkou, jaký bude mít koncern vliv na životní cyklus aspektově orientovaného kódu.
[editovat] Implementace
- Java:
- AspectJ
- AspectWerkz (Now merged with AspectJ)
- Byte Code Engineering Library
- Dynaop
- JAC
- Jakarta Hivemind
- Javassist Home Page
- JAsCo
- JAML
- JBoss AOP
- Object Teams
- PROSE
- Reflex
- The AspectBench Compiler for AspectJ (abc)
- The Spring Framework as part of its functionality
- Seasar
- The JMangler Project
- InjectJ
- C/C++:
- Python:
- Lightweight Python AOP
- Logilab's aspect module
- Python/Transwarp AOP Tutorial (Replaced by PEAK)
- PEAK
- Pythius
- Common Lisp:
- Cocoa:
Write your own preprocessing system.
- For More Info (real-world implementations):
[editovat] Publikace
- Kiczales, Gregor, John Lamping, Anurag Mendhekar, Chris Maeda, Cristina Lopes, Jean-Marc Loingtier, and John Irwin (1997). „Aspect-Oriented Programming“ Proceedings of the European Conference on Object-Oriented Programming, vol.1241, pp.220–242. Tento papír je původcem AOP.
- Filman, Robert E., Tzilla Elrad, Siobhan Clarke, and Mehmet Aksit. Aspect-Oriented Software Development. ISBN 0-321-21976-7.
- Pawlak, Renaud, Lionel Seinturier, and Jean-Philippe Retaillé. Foundations of AOP for J2EE Development. ISBN 1-59059-507-6.
- Laddad, Ramnivas. AspectJ in Action: Practical Aspect-Oriented Programming. ISBN 1-930110-93-6.
- Jacobson, Ivar, and Pan-Wei Ng. Aspect-Oriented Software Development with Use Cases. ISBN 0-321-26888-1.
[editovat] Externí odkazy
- Aspect-Oriented Software Development (annual conference about AOP)
- AOSD Wiki (Wiki specifically devoted to AOP)
- AspectJ (Java implementation)
- The AspectBench Compiler for AspectJ (another Java implementation)
- A detailed series of articles about the basics of aspect-oriented programming and AspectJ
- Introduction to Aspect Oriented Programming with RemObjects Taco
- Constraint-Specification Aspect Weaver
- Aspect- vs. Object-Oriented Programming: Which Technique, When?
- Light-weight Approach to AOP for Python