Programmazione orientata agli aspetti vs. programmazione orientata agli oggetti


199

Come la maggior parte degli sviluppatori qui e in tutto il mondo, ho sviluppato sistemi software utilizzando tecniche di programmazione orientata agli oggetti (OOP) per molti anni. Quindi, quando leggo che la programmazione orientata all'aspetto (AOP) affronta molti dei problemi che OOP tradizionale non risolve completamente o direttamente, mi fermo e penso, è reale?

Ho letto molte informazioni cercando di apprendere le chiavi di questo paradigma AOP e sono nello stesso posto, quindi volevo capire meglio i suoi benefici nello sviluppo di applicazioni nel mondo reale.

Qualcuno ha la risposta?


7
Tutte le risposte sono state molto buone, questo è il caso perfetto per una singola risposta modificata dalla community che le combinerebbe tutte.
Stanno

Risposte:


323

Perché "vs"? Non è "vs". È possibile utilizzare la programmazione orientata agli aspetti in combinazione con la programmazione funzionale, ma anche in combinazione con la programmazione orientata agli oggetti. Non è "vs", è "Programmazione orientata agli aspetti con programmazione orientata agli oggetti".

Per me AOP è una sorta di "meta-programmazione". Tutto ciò che fa AOP potrebbe anche essere fatto senza di esso semplicemente aggiungendo più codice. AOP ti salva semplicemente scrivendo questo codice.

Wikipedia ha uno dei migliori esempi per questa meta-programmazione. Supponiamo di avere una classe grafica con molti metodi "set ... ()". Dopo ogni metodo impostato, i dati della grafica sono cambiati, quindi la grafica è cambiata e quindi la grafica deve essere aggiornata sullo schermo. Supponiamo di ridipingere la grafica che devi chiamare "Display.update ()". L'approccio classico è quello di risolvere questo aggiungendo più codice . Alla fine di ogni metodo impostato che scrivi

void set...(...) {
    :
    :
    Display.update();
}

Se hai 3 metodi set, questo non è un problema. Se ne hai 200 (ipotetici), diventa davvero doloroso aggiungerlo ovunque. Inoltre, ogni volta che aggiungi un nuovo metodo set, devi essere sicuro di non dimenticare di aggiungere questo alla fine, altrimenti hai appena creato un bug.

AOP risolve questo problema senza aggiungere tonnellate di codice, invece aggiungi un aspetto:

after() : set() {
   Display.update();
}

E questo è tutto! Invece di scrivere tu stesso il codice di aggiornamento, devi solo dire al sistema che dopo che è stato raggiunto un set point (), deve eseguire questo codice ed eseguirà questo codice. Non è necessario aggiornare 200 metodi, non è necessario assicurarsi di non dimenticare di aggiungere questo codice su un nuovo metodo set. Inoltre hai solo bisogno di un taglio:

pointcut set() : execution(* set*(*) ) && this(MyGraphicsClass) && within(com.company.*);

Cosa significa? Ciò significa che se un metodo è chiamato "set *" (* significa che qualsiasi nome potrebbe seguire dopo set), indipendentemente da ciò che il metodo restituisce (primo asterisco) o quali parametri prende (terzo asterisco) ed è un metodo di MyGraphicsClass e questo class fa parte del pacchetto "com.company. *", quindi si tratta di un setpoint () pointcut. E il nostro primo codice dice " dopo eseguito qualsiasi metodo che sia un set pointcut, eseguire il codice seguente".

Vedi come AOP risolve elegantemente il problema qui? In realtà tutto ciò che è descritto qui può essere fatto in fase di compilazione. Un preprocessore AOP può semplicemente modificare la sorgente (ad esempio aggiungendo Display.update () alla fine di ogni metodo set-pointcut) prima di compilare la classe stessa.

Tuttavia, questo esempio mostra anche uno dei principali svantaggi di AOP. AOP sta effettivamente facendo qualcosa che molti programmatori considerano un " Anti-Pattern ". Il modello esatto si chiama " Azione a distanza ".

L'azione a distanza è un anti-modello (un errore comune riconosciuto) in cui il comportamento in una parte di un programma varia in modo selvaggio sulla base di operazioni difficili o impossibili da identificare in un'altra parte del programma.

Come novizio di un progetto, potrei semplicemente leggere il codice di qualsiasi metodo set e considerarlo non funzionante, in quanto sembra non aggiornare il display. Non vedo solo guardando il codice di un metodo set, che dopo che è stato eseguito, qualche altro codice verrà "magicamente" eseguito per aggiornare il display. Lo considero un aspetto negativo! Modificando un metodo, potrebbero essere introdotti strani bug. Comprendere ulteriormente il flusso di codice del codice in cui certe cose sembrano funzionare correttamente, ma non sono ovvie (come ho detto, funzionano magicamente ... in qualche modo), è davvero difficile.

Aggiornare

Giusto per chiarire che: alcune persone potrebbero avere l'impressione che sto dicendo che AOP sia qualcosa di brutto e non dovrebbe essere usato. Non è quello che sto dicendo! AOP è in realtà una grande funzionalità. Dico solo "Usalo attentamente". AOP causerà problemi solo se si confondono codice normale e AOP per lo stesso aspetto . Nell'esempio sopra, abbiamo l'aspetto di aggiornare i valori di un oggetto grafico e dipingere l'oggetto aggiornato. Questo è in effetti un singolo aspetto. La codifica della metà come codice normale e l'altra metà come aspetto è ciò che aggiunge il problema.

Se si utilizza AOP per un aspetto completamente diverso, ad esempio per la registrazione, non si verificherà il problema dell'anti-pattern. In tal caso, un novizio del progetto potrebbe chiedersi "Da dove provengono tutti questi messaggi di registro? Non vedo alcun output di registro nel codice", ma questo non è un grosso problema. Le modifiche apportate alla logica del programma difficilmente rompono la funzione di registro e le modifiche apportate alla funzione di registro difficilmente rompono la sua logica del programma - questi aspetti sono totalmente separati. L'uso di AOP per la registrazione ha il vantaggio che il codice del programma può concentrarsi completamente sul fare tutto ciò che dovrebbe fare e puoi comunque avere una registrazione sofisticata, senza che il tuo codice sia ingombro da centinaia di messaggi di registro ovunque. Inoltre, quando viene introdotto un nuovo codice, i messaggi di log magici appariranno al momento giusto con il contenuto giusto.

Quindi un buon uso di AOP nel mio esempio sarebbe quello di registrare sempre se qualche valore è stato aggiornato tramite un metodo impostato. Questo non creerà un anti-pattern e difficilmente sarà la causa di alcun problema.

Si potrebbe dire, se si può facilmente abusare di AOP per creare così tanti problemi, è una cattiva idea usarlo tutto. Tuttavia, quale tecnologia non può essere abusata? Puoi abusare dell'incapsulamento dei dati, puoi abusare dell'eredità. Praticamente ogni utile tecnologia di programmazione può essere abusata. Considera un linguaggio di programmazione così limitato da contenere solo funzionalità che non possono essere abusate; una lingua in cui le funzionalità possono essere utilizzate solo come inizialmente erano destinate a essere utilizzate. Un linguaggio del genere sarebbe così limitato che è discutibile se può anche essere usato per la programmazione nel mondo reale.


4
La registrazione sembra essere un esempio specifico in cui AOP non si traduce in Azione a distanza. In questo momento, Wikipedia come esempio dell'uso dell'aspetto per cose come i controlli di sicurezza, che rendono il flusso del programma molto più comprensibile.
kizzx2,

7
@ kizzx2: ottimo punto sul logging, infatti - è il miglior esempio che ho visto finora la forza di AOP, senza sapere molto su AOP. Grazie per la condivisione!
errori del

@Mecki, il tuo esempio è eccessivamente semplificato e non riflette il caso d'uso generale. Nel tuo esempio, Display.updatenon accetta argomenti. E se avessimo bisogno di passare argomenti (ad es. Di solito una logfunzione richiederebbe un messageparametro)? Non avremmo quindi bisogno di aggiungere un sacco di codice boilerplate per farlo nel modo AOP?
Pacerier,

3
@Pacerier Il mio esempio è semplificato perché SO non è un forum di insegnamento. Stavo solo rispondendo alla domanda dell'interrogante, probabilmente molto più dettagliata di quanto sarebbe stato necessario. Se vuoi saperne di più su AOP, prova a leggere la documentazione del programmatore e se hai una domanda dettagliata, perché non farla qui? No, non in un commento, vai e crea una nuova domanda perché questo è tutto ciò che riguarda SO. Sono sicuro che qualcuno sarà in grado di dissipare i tuoi dubbi in una risposta.
Mecki,

2
@Pacerier Siamo spiacenti, ma non riesco a vedere il tuo punto. Vedi qui: stackoverflow.com/a/8843713/15809 Questo codice registra ogni chiamata a tutti i metodi pubblici, inclusi tutti i tipi e i valori degli argomenti del metodo. Lo scrivi esattamente una volta e non viene aggiunto alcun codice del boilerplate a nessun metodo, è solo il codice mostrato nella risposta.
Mecki,

29

Il pogramming orientato all'aspetto offre un modo piacevole per implementare preoccupazioni trasversali come la registrazione, la sicurezza. Queste concerzioni trasversali sono elementi logici che devono essere applicati in molti luoghi, ma in realtà non hanno nulla a che fare con la logica aziendale.

Non dovresti vedere AOP come un sostituto di OOP, piuttosto come un bel componente aggiuntivo, che rende il tuo codice più pulito, accoppiato liberamente e focalizzato sulla logica aziendale. Quindi applicando AOP otterrai 2 vantaggi principali:

  1. La logica di ogni preoccupazione è ora in un posto, invece di essere sparsa in tutta la base di codice.

  2. le classi sono più pulite poiché contengono solo codice per la loro preoccupazione principale (o funzionalità principale) e le preoccupazioni secondarie sono state spostate su aspetti.


27

OOP e AOP non si escludono a vicenda. AOP può essere una buona aggiunta a OOP. AOP è particolarmente utile per aggiungere codice standard come registrazione, tracciamento delle prestazioni, ecc. Ai metodi senza intasare il codice del metodo con questo codice standard.


10

Penso che non ci sia una risposta generale a questa domanda, ma una cosa da notare è che AOP non sostituisce OOP ma aggiunge alcune caratteristiche di decomposizione che affrontano la cosiddetta tirannia della composizione dominante ( 1 ) (o preoccupazioni trasversali).

Sicuramente aiuta in alcuni casi fino a quando hai il controllo degli strumenti e delle lingue da utilizzare per un progetto specifico, ma aggiunge anche un nuovo livello di complessità per quanto riguarda l'interazione degli aspetti e la necessità di strumenti aggiuntivi come l' AJDT per capire ancora il tuo programma.

Gregor Kiczales una volta ha tenuto un interessante discorso introduttivo su AOP a Google Tech Talks che consiglio di guardare: Programmazione orientata agli aspetti: Ricerca radicale nella modularità .


8

Prima di tutto, AOP non sostituirà OOP. AOP estende OOP. Le idee e le pratiche di OOP rimangono pertinenti. Avere un buon design degli oggetti probabilmente renderà più facile estenderlo con gli aspetti.

Penso che le idee che porta AOP siano importanti. Dobbiamo trovare modi per attuare preoccupazioni trasversali su diverse classi del tuo programma senza dover cambiare le classi stesse. Ma penso che l'AOP alla fine diventerà parte di altri strumenti che usiamo e non uno strumento o una tecnica separati. Lo vediamo già accadere.

Un paio di linguaggi dinamici come Ruby e Python hanno costrutti linguistici come mixin che risolvono gli stessi problemi. Assomiglia molto ad AOP ma è meglio integrato nella lingua.

Spring e Castle e un paio di altri framework di iniezione di dipendenza hanno opzioni per aggiungere comportamento alle classi che iniettano. Questo è un modo di fare la tessitura runtime e penso che questo abbia un grande potenziale.

Non credo che dovrai imparare un paradigma completamente nuovo per usare AOP. Le idee sono interessanti ma vengono lentamente assorbite dagli strumenti e dalle lingue esistenti. Tieniti informato e prova questi strumenti.



1

Sono in ritardo per rispondere a questa domanda, ma è uno dei miei argomenti preferiti, quindi lasciami condividere la mia opinione.

OOP viene utilizzato principalmente per organizzare la logica aziendale, mentre AOP aiuta a organizzare le cose non funzionali come il controllo, la registrazione, la gestione delle transazioni, la sicurezza ecc.

In questo modo è possibile disaccoppiare la logica aziendale con una logica non fittizia che rende il codice più pulito.

Il vantaggio principale è che puoi applicare i consigli (esempio di controllo) in modo molto coerente senza implementare alcuna interfaccia che offra grande flessibilità per le modifiche senza toccare la logica aziendale

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.