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.