Aspektově orientované programování: Porovnání verzí

Z Wikipedie, otevřené encyklopedie
Smazaný obsah Přidaný obsah
m Robot: -zastaralá značka HTML
doplnění, typo
 
Řádek 1: Řádek 1:
{{Programovací paradigmata}}
{{Programovací paradigmata}}
'''Aspektově orientované programování''' (zkracováno na '''AOP''', z anglického '''Aspect Oriented Programming''') je [[programovací paradigma]], které má za cíl zvýšit modularitu programu. Pokouší se rozdělit program na jasné části, které se mezi sebou co nejméně překrývají svou funkcionalitou.
'''Aspektově orientované programování''' (zkracováno na '''AOP''', z anglického '''Aspect Oriented Programming''') je [[programovací paradigma]], které má za cíl zvýšit modularitu programu. Pokouší se rozdělit program na jasné části, které se mezi sebou co nejméně překrývají svou funkcionalitou. AOP se začalo hojně používat zejména v roce 2004.
AOP se začalo hojně používat zejména v roce 2004.
== Úvod ==
== Úvod ==
Většina programovacích paradigmat podporuje určitou úroveň seskupení a zapouzdření dat do samostatných, nezávislých subjektů. Některé však vzdorují této formě implementace a jsou nazývány ''průřezové problémy ([[cross-cutting concerns|crosscutting concerns]])'', protože se nachází ve více částech programu.
Většina programovacích paradigmat podporuje určitou úroveň seskupení a zapouzdření dat do samostatných, nezávislých subjektů. Některé však vzdorují této formě implementace a jsou nazývány ''průřezové problémy ([[cross-cutting concerns|crosscutting concerns]])'', protože se nachází ve více částech programu. AOP má za cíl nahradit v kódu opakující se činnosti, vzorovým příkladem průřezového problému je [[log]]ování, protože se týká každé jednotlivé logované části programu. Logování tedy ''prořezává'' všechny logované třídy, metody i procedury. Všechny implementace AOP mají nějaké průřezové výrazy, které zapouzdří danou činnost na konkrétním místě. Rozdíl mezi implementacemi spočívá v náročnosti, bezpečnosti a použitelnosti poskytnutých konstrukcí. [[AspectJ]] má řadu těchto výrazů a zapouzdřuje je ve speciální třídě, zvané [[Aspekt (programování)|aspekt]]. Aspekt může upravit chování základního kódu (neaspektové části programu) použitím ''advice'' (dodatečné chování) v různých ''joinpoints'' (body ve struktuře programu), zvaný ''pointcut'' (soubor joinpointů, pro které je spouštěna stejná advice). Aspekt také může dělat binárně kompatibilní strukturální změny jiných tříd, což je například přidání členů nebo rodičů.
AOP má za cíl nahradit v kódu opakující se činnosti, vzorovým příkladem průřezového problému je
[[log]]ování, protože se týká každé jednotlivé logované části programu. Logování tedy ''prořezává'' všechny logované třídy, metody i procedury.
Všechny implementace AOP mají nějaké průřezové výrazy, které zapouzdří danou činnost na konkrétním místě. Rozdíl mezi implementacemi spočívá v náročnosti, bezpečnosti a použitelnosti poskytnutých konstrukcí. [[AspectJ]] má řadu těchto výrazů a zapouzdřuje je ve speciální třídě, zvané [[Aspekt (programování)|aspekt]]. Aspekt může upravit chování základního kódu (neaspektové části programu) použitím ''advice'' (dodatečné chování) v různých ''joinpoints'' (body ve struktuře programu), zvaný ''pointcut'' (soubor joinpointů, pro které je spouštěna stejná advice). Aspekt také může dělat binárně kompatibilní strukturální změny jiných tříd, což je například přidání členů nebo rodičů.


== Historie ==
== Historie ==
Řádek 21: Řádek 17:
Statické AOP je rychlejší než dynamické, jelikož [[aspect weaver|weaving]] (proces vkládání aspektů do aplikace) probíhá již při buildu aplikace, přibývá zde další krok, avšak kód AOP již při běhu aplikace nelze měnit. Potřebujeme-li tedy udělat jakoukoli změnu za běhu aplikace, jsme nuceni k opětovné kompilaci celé aplikace. Statické AOP se používá například v již zmiňovaném AspectJ.
Statické AOP je rychlejší než dynamické, jelikož [[aspect weaver|weaving]] (proces vkládání aspektů do aplikace) probíhá již při buildu aplikace, přibývá zde další krok, avšak kód AOP již při běhu aplikace nelze měnit. Potřebujeme-li tedy udělat jakoukoli změnu za běhu aplikace, jsme nuceni k opětovné kompilaci celé aplikace. Statické AOP se používá například v již zmiňovaném AspectJ.
=== Dynamické AOP ===
=== Dynamické AOP ===
Dynamické AOP je sice, oproti statickému, pomalejší, ale můžeme měnit kód zcela nezávisle na aplikaci. Změny v AOP tedy neznamenají nutnou opětovnou kompilaci celé aplikace. Je to způsobené tím, že u dynamických AOP probíhá weaving až při běhu aplikace. U různých implementací je toho dosaženo za pomoci různých technik, nejčastěji je však používáno proxy pro každý objekt, který využívá aspekty.
Dynamické AOP je sice oproti statickému AOP pomalejší, ale můžeme měnit kód zcela nezávisle na aplikaci. Změny v AOP tedy neznamenají nutnou opětovnou kompilaci celé aplikace. Je to způsobené tím, že u dynamických AOP probíhá weaving až při běhu aplikace. U různých implementací je toho dosaženo za pomoci různých technik, nejčastěji je však používáno proxy pro každý objekt, který využívá aspekty.


== Motivace a základní koncepty ==
== Motivace a základní koncepty ==
Aspekt je typicky rozptýlen jako kód, takže není zcela lehké ho pochopit a udržovat. Aspekt je rozptýlen na základě funkce (například logování) a je rozložen do několika nesouvisejících funkcí, které by mohly používat jeho funkce, případně ve zcela nesouvisejících systémech, různých zdrojových jazycích atd. To znamená, že ke změně logování může vyžadovat modifikaci všech dotyčných modulů. Aspekty nejsou “zamotané” pouze s hlavními funkcemi systému, ve kterém jsou vyjádřené, ale i mezi sebou navzájem.
Aspekt je typicky rozptýlen jako kód, takže není zcela lehké ho pochopit a udržovat. Aspekt je rozptýlen na základě funkce (například logování) a je rozložen do několika nesouvisejících funkcí, které by mohly používat jeho funkce, případně ve zcela nesouvisejících systémech, různých zdrojových jazycích atd. To znamená, že ke změně logování může vyžadovat modifikaci všech dotyčných modulů. Aspekty nejsou “zamotané” pouze s hlavními funkcemi systému, ve kterém jsou vyjádřené, ale i mezi sebou navzájem. Například si představme bankovní aplikaci s koncepčně velmi jednoduchou metodou na převod částky z jednoho účtu na druhý:<ref>Poznámka: Pro ukázky v tomto článku je použita syntaxe jazyka [[Java (programovací jazyk)|Java]].</ref>
Například si představme bankovní aplikaci s koncepčně velmi jednoduchou metodou na převod částky z jednoho účtu na druhý:<ref>Poznámka: Pro ukázky v tomto článku je použita syntaxe jazyka [[Java (programovací jazyk)|Java]].</ref>


<syntaxhighlight lang="java">
<syntaxhighlight lang="java">
Řádek 37: Řádek 32:
</syntaxhighlight>
</syntaxhighlight>


Nicméně, tato metoda pro převod peněz mezi účty je velice vzdálená reálným bankovním aplikacím, jelikož, kvůli bezpečnosti, musíme ověřit, zda má aktuální uživatel autorizaci k provedení této operace. Musíme také uzavřít tuto operaci do [[Databázová transakce|databázové transakce]], abychom předešli nekonzistenci dat. Zjednodušená verze s těmito novými koncerny (problémy) by mohla vypadat nějak takto:

Nicméně, tato metoda pro převod peněz mezi účty je velice vzdálená reálným bankovním aplikacím, jelikož, kvůli bezpečnosti, musíme ověřit, zda má aktuální uživatel autorizaci k provedení této operace. Musíme také uzavřít tuto operaci do [[Databázová transakce|databázové transakce]], abychom předešli nekonzistenci dat.
Zjednodušená verze s těmito novými koncerny by mohla vypadat nějak takto:


<syntaxhighlight lang="java">
<syntaxhighlight lang="java">
Řádek 64: Řádek 57:
</syntaxhighlight>
</syntaxhighlight>


Kód již není tak jednoduchý a elegantní, jelikož jsme přidali různé další koncerny (problémy) k základní funkcionalitě (někdy zvané ''koncern obchodní logiky''). Transakce, zabezpečení a logování jsou příklady ''průřezových problémů''. Nyní si představme, co se stane, když najednou potřebujeme změnit (například) bezpečnostní schéma pro danou aplikaci. V současné verzi programu jsou operace týkající se zabezpečení “rozesety” v mnoha metodách, a tak by změna vyžadovala značné úsilí. AOP se snaží tento problém vyřešit tím, že programátor vyjádří ''průřezové problémy'' v samostatných modulech zvaných aspekty. Aspekty mohou obsahovat ''advice'' (kód spojený s určitými body v programu) a ''inter-type declarations'' (rozšíření deklarace tříd). Například bezpečnostní modul může obsahovat ''advice'', který provádí bezpečnostní kontrolu před vstupem do bankovního účtu. ''Pointcut'' definuje dobu (''join points''), kdy je možné získat přístup k bankovnímu účtu a kód v těle ''advice'' určuje, jak je bezpečnostní kontrola implementována. To je způsob, jak mohou být kontrola a místo udržovány na jednom místě. Dobrý ''pointcut'', také může předvídat pozdější programové změny, takže pokud jiný vývojář vytvoří novou metodu pro přístup k bankovnímu účtu, ''advice'' se bude vztahovat i na nové metody, při jejich provádění. Takže takto se pro výše uvedený příklad provádí záznam v aspektu:
Kód již není tak jednoduchý a elegantní, jelikož jsme přidali různé další koncerny k základní funkcionalitě (někdy zvané ''koncern obchodní logiky''). Transakce, zabezpečení a logování jsou příklady ''průřezových problémů''.
Nyní si představme, co se stane, když najednou potřebujeme změnit (například) bezpečnostní schéma pro danou aplikaci. V současné verzi programu jsou operace týkající se zabezpečení “rozesety” v mnoha metodách, a tak by změna vyžadovala značné úsilí.
AOP se snaží tento problém vyřešit tím, že programátor vyjádří ''průřezové problémy'' v samostatných modulech zvaných aspekty. Aspekty mohou obsahovat ''advice'' (kód spojený s určitými body v programu) a ''inter-type declarations'' (rozšíření deklarace tříd). Například bezpečnostní modul může obsahovat ''advice'', který provádí bezpečnostní kontrolu před vstupem do bankovního účtu. ''Pointcut'' definuje dobu (''join points''), kdy je možné získat přístup k bankovnímu účtu a kód v těle ''advice'' určuje, jak je bezpečnostní kontrola implementována. To je způsob, jak mohou být kontrola a místo udržovány na jednom místě. Dobrý ''pointcut'', také může předvídat pozdější programové změny, takže pokud jiný vývojář vytvoří novou metodu pro přístup k bankovnímu účtu, ''advice'' se bude vztahovat i na nové metody, při jejich provádění.
Takže takto se pro výše uvedený příklad provádí záznam v aspektu:


<syntaxhighlight lang="java">
<syntaxhighlight lang="java">
Řádek 85: Řádek 75:
== Join point modely (JPM) ==
== Join point modely (JPM) ==
Způsob spolupráce aspektu s programem je definován v ''join point modelu'' (z anglického join point model). JPM definuje tři věci:
Způsob spolupráce aspektu s programem je definován v ''join point modelu'' (z anglického join point model). JPM definuje tři věci:
Join points - místa, do kterých je možné do kódu vložit logiku pomocí AOP
Join points - místa, do kterých je možné do kódu vložit logiku pomocí AOP Advice - kód, který se spouští v ''join'' pointu, může se spouštět před (''before'') i za (''after'') ''join pointem''
Advice - kód, který se spouští v ''join'' pointu, může se spouštět před (''before'') i za (''after'') ''join pointem''
Pointcut - je soubor ''join pointů'', ve kterých je spuštěna stejná ''advice''
Pointcut - je soubor ''join pointů'', ve kterých je spuštěna stejná ''advice''
== Srovnání s jinými programovacími paradigmaty ==
== Srovnání s jinými programovacími paradigmaty ==

Aktuální verze z 2. 4. 2021, 19:33

Programovací paradigmata

Aspektově orientované programování (zkracováno na AOP, z anglického Aspect Oriented Programming) je programovací paradigma, které má za cíl zvýšit modularitu programu. Pokouší se rozdělit program na jasné části, které se mezi sebou co nejméně překrývají svou funkcionalitou. AOP se začalo hojně používat zejména v roce 2004.

Úvod[editovat | editovat zdroj]

Většina programovacích paradigmat podporuje určitou úroveň seskupení a zapouzdření dat do samostatných, nezávislých subjektů. Některé však vzdorují této formě implementace a jsou nazývány průřezové problémy (crosscutting concerns), protože se nachází ve více částech programu. AOP má za cíl nahradit v kódu opakující se činnosti, vzorovým příkladem průřezového problému je logování, protože se týká každé jednotlivé logované části programu. Logování tedy prořezává všechny logované třídy, metody i procedury. Všechny implementace AOP mají nějaké průřezové výrazy, které zapouzdří danou činnost na konkrétním místě. Rozdíl mezi implementacemi spočívá v náročnosti, bezpečnosti a použitelnosti poskytnutých konstrukcí. AspectJ má řadu těchto výrazů a zapouzdřuje je ve speciální třídě, zvané aspekt. Aspekt může upravit chování základního kódu (neaspektové části programu) použitím advice (dodatečné chování) v různých joinpoints (body ve struktuře programu), zvaný pointcut (soubor joinpointů, pro které je spouštěna stejná advice). Aspekt také může dělat binárně kompatibilní strukturální změny jiných tříd, což je například přidání členů nebo rodičů.

Historie[editovat | editovat zdroj]

Aspektově orientované programování má několik přímých předchůdců: reflexe a metaobjektové protokoly, objektové programování, filtry a adaptivní programování.

Tento koncept vymyslel Gregor Kiczales s kolegy v Xerox PARC. Stejný tým vyvinul i první a zatím nejpoužívanější aspektově orientovaný jazyk AspectJ.

Microsoft Transaction Server je považován za první hlavní použití AOP následovaný Enterprise Java Beans.

Typy aspektově orientovaného programování[editovat | editovat zdroj]

AOP se dá rozdělit na statické a dynamické. Statické AOP poskytuje například AspectJ a dynamické Spring Framework.

Statické AOP[editovat | editovat zdroj]

Statické AOP je rychlejší než dynamické, jelikož weaving (proces vkládání aspektů do aplikace) probíhá již při buildu aplikace, přibývá zde další krok, avšak kód AOP již při běhu aplikace nelze měnit. Potřebujeme-li tedy udělat jakoukoli změnu za běhu aplikace, jsme nuceni k opětovné kompilaci celé aplikace. Statické AOP se používá například v již zmiňovaném AspectJ.

Dynamické AOP[editovat | editovat zdroj]

Dynamické AOP je sice oproti statickému AOP pomalejší, ale můžeme měnit kód zcela nezávisle na aplikaci. Změny v AOP tedy neznamenají nutnou opětovnou kompilaci celé aplikace. Je to způsobené tím, že u dynamických AOP probíhá weaving až při běhu aplikace. U různých implementací je toho dosaženo za pomoci různých technik, nejčastěji je však používáno proxy pro každý objekt, který využívá aspekty.

Motivace a základní koncepty[editovat | editovat zdroj]

Aspekt je typicky rozptýlen jako kód, takže není zcela lehké ho pochopit a udržovat. Aspekt je rozptýlen na základě funkce (například logování) a je rozložen do několika nesouvisejících funkcí, které by mohly používat jeho funkce, případně ve zcela nesouvisejících systémech, různých zdrojových jazycích atd. To znamená, že ke změně logování může vyžadovat modifikaci všech dotyčných modulů. Aspekty nejsou “zamotané” pouze s hlavními funkcemi systému, ve kterém jsou vyjádřené, ale i mezi sebou navzájem. Například si představme bankovní aplikaci s koncepčně velmi jednoduchou metodou na převod částky z jednoho účtu na druhý:[1]

void transfer(Account fromAcc, Account toAcc, int amount) throws Exception {
   if (fromAcc.getBalance() < amount)
      throw new InsufficientFundsException();

   fromAcc.withdraw(amount);
   toAcc.deposit(amount);
}

Nicméně, tato metoda pro převod peněz mezi účty je velice vzdálená reálným bankovním aplikacím, jelikož, kvůli bezpečnosti, musíme ověřit, zda má aktuální uživatel autorizaci k provedení této operace. Musíme také uzavřít tuto operaci do databázové transakce, abychom předešli nekonzistenci dat. Zjednodušená verze s těmito novými koncerny (problémy) by mohla vypadat nějak takto:

void transfer(Account fromAcc, Account toAcc, int amount, User user, Logger logger) 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.");
}

Kód již není tak jednoduchý a elegantní, jelikož jsme přidali různé další koncerny (problémy) k základní funkcionalitě (někdy zvané koncern obchodní logiky). Transakce, zabezpečení a logování jsou příklady průřezových problémů. Nyní si představme, co se stane, když najednou potřebujeme změnit (například) bezpečnostní schéma pro danou aplikaci. V současné verzi programu jsou operace týkající se zabezpečení “rozesety” v mnoha metodách, a tak by změna vyžadovala značné úsilí. AOP se snaží tento problém vyřešit tím, že programátor vyjádří průřezové problémy v samostatných modulech zvaných aspekty. Aspekty mohou obsahovat advice (kód spojený s určitými body v programu) a inter-type declarations (rozšíření deklarace tříd). Například bezpečnostní modul může obsahovat advice, který provádí bezpečnostní kontrolu před vstupem do bankovního účtu. Pointcut definuje dobu (join points), kdy je možné získat přístup k bankovnímu účtu a kód v těle advice určuje, jak je bezpečnostní kontrola implementována. To je způsob, jak mohou být kontrola a místo udržovány na jednom místě. Dobrý pointcut, také může předvídat pozdější programové změny, takže pokud jiný vývojář vytvoří novou metodu pro přístup k bankovnímu účtu, advice se bude vztahovat i na nové metody, při jejich provádění. Takže takto se pro výše uvedený příklad provádí záznam v aspektu:

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

Join point modely (JPM)[editovat | editovat zdroj]

Způsob spolupráce aspektu s programem je definován v join point modelu (z anglického join point model). JPM definuje tři věci: Join points - místa, do kterých je možné do kódu vložit logiku pomocí AOP Advice - kód, který se spouští v join pointu, může se spouštět před (before) i za (after) join pointem Pointcut - je soubor join pointů, ve kterých je spuštěna stejná advice

Srovnání s jinými programovacími paradigmaty[editovat | editovat zdroj]

Aspekty vycházejí z objektově orientovaného programování (OOP). AOP jazyky nabízí podobné funkce jako metaobject protokoly. Aspekty úzce souvisí s programovacími koncepty jako subjekty, mixiny a delegace. Již od roku 1970 vývojáři používali formy odposlechu (interception) a záplatování (dispatch-patching), které se podobají některým ze způsobů implementace pro AOP, ale nikdy nebyly označovány jako cross cutting specifikace a sepsány na jednom místě. Návrháři zvažovali i jiné způsoby, jak dosáhnout odděleného kódu, jako jsou například dílčí typy (partial types) v C#, těmto přístupům však chybí kvantifikační mechanismus, který umožňuje propojení několika join pointů s jednou deklarací.

Reference[editovat | editovat zdroj]

  1. Poznámka: Pro ukázky v tomto článku je použita syntaxe jazyka Java.