Por que "vs"? Não é "vs". Você pode usar a programação Orientada a Aspectos em combinação com a programação funcional, mas também em combinação com a Orientada a Objetos. Não é "vs", é "Programação Orientada a Aspectos com Programação Orientada a Objetos".
Para mim, AOP é algum tipo de "meta-programação". Tudo o que a AOP faz também pode ser feito sem a adição de mais código. AOP apenas poupa você escrevendo este código.
A Wikipedia tem um dos melhores exemplos para essa meta-programação. Suponha que você tenha uma classe gráfica com muitos métodos "set ... ()". Após cada método definido, os dados dos gráficos foram alterados, assim os gráficos foram alterados e, portanto, os gráficos precisam ser atualizados na tela. Suponha que repintar os gráficos que você deve chamar "Display.update ()". A abordagem clássica é resolver isso adicionando mais código . No final de cada método definido, você escreve
void set...(...) {
:
:
Display.update();
}
Se você possui três métodos de conjunto, isso não é um problema. Se você tem 200 (hipotético), é realmente doloroso adicionar isso em qualquer lugar. Além disso, sempre que você adicionar um novo método de conjunto, lembre-se de não esquecer de adicioná-lo ao final, caso contrário, você acabou de criar um bug.
AOP resolve isso sem adicionar toneladas de código; em vez disso, você adiciona um aspecto:
after() : set() {
Display.update();
}
E é isso! Em vez de escrever o código de atualização você mesmo, basta informar ao sistema que, após um pointcut set () ter sido atingido, ele deve executar esse código e executá-lo. Não é necessário atualizar 200 métodos, não se esqueça de adicionar este código em um novo método definido. Além disso, você só precisa de um pointcut:
pointcut set() : execution(* set*(*) ) && this(MyGraphicsClass) && within(com.company.*);
O que isso significa? Isso significa que se um método for chamado "conjunto *" (* significa que qualquer nome pode seguir após o conjunto), independentemente do retorno do método (primeiro asterisco) ou dos parâmetros necessários (terceiro asterisco) e é um método de MyGraphicsClass e este class faz parte do pacote "com.company. *", então este é um pointcut set (). E nosso primeiro código diz " depois executar qualquer método que seja um set pointcut, execute o seguinte código".
Veja como a AOP resolve elegantemente o problema aqui? Na verdade, tudo o que é descrito aqui pode ser feito em tempo de compilação. Um pré-processador AOP pode apenas modificar sua fonte (por exemplo, adicionar Display.update () ao final de cada método de setpoint) antes mesmo de compilar a própria classe.
No entanto, este exemplo também mostra uma das grandes desvantagens da AOP. AOP está realmente fazendo algo que muitos programadores consideram um " Antipadrão ". O padrão exato é chamado " Ação à distância ".
Ação à distância é um antipadrão (um erro comum reconhecido) no qual o comportamento em uma parte de um programa varia muito com base em operações difíceis ou impossíveis de identificar em outra parte do programa.
Como iniciante em um projeto, posso ler o código de qualquer método definido e considerá-lo quebrado, pois parece não atualizar a exibição. Não vejo apenas olhando para o código de um método set que, depois de executado, algum outro código será "magicamente" executado para atualizar a exibição. Considero isso uma desvantagem séria! Fazendo alterações em um método, erros estranhos podem ser introduzidos. Compreender melhor o fluxo de código onde certas coisas parecem funcionar corretamente, mas não são óbvias (como eu disse, elas funcionam magicamente ... de alguma forma), é realmente difícil.
Atualizar
Só para esclarecer isso: algumas pessoas podem ter a impressão de que estou dizendo que AOP é algo ruim e não deve ser usado. Não é isso que estou dizendo! AOP é realmente um ótimo recurso. Eu apenas digo "Use-o com cuidado". AOP só causará problemas se você misturar código normal e AOP para o mesmo Aspecto . No exemplo acima, temos o Aspecto de atualizar os valores de um objeto gráfico e pintar o objeto atualizado. Na verdade, esse é um aspecto único. Codificar metade dele como código normal e a outra metade como aspecto é o que adiciona o problema.
Se você usar o AOP para um aspecto completamente diferente, por exemplo, para o registro, não encontrará o problema antipadrão. Nesse caso, um iniciante no projeto pode se perguntar "De onde vêm todas essas mensagens de log? Não vejo nenhuma saída de log no código", mas isso não é um grande problema. As alterações que ele faz na lógica do programa dificilmente quebram o recurso de log e as alterações feitas no recurso de log dificilmente quebram a lógica do programa - esses aspectos são totalmente separados. O uso do AOP para o log possui a vantagem de que o código do programa pode se concentrar totalmente em fazer o que deve ser feito e você ainda pode ter um log sofisticado, sem que o seu código seja desordenado por centenas de mensagens de log em todos os lugares. Além disso, quando um novo código é introduzido, as mensagens de log magicamente aparecerão no momento certo, com o conteúdo certo.
Portanto, um bom uso do AOP no meu exemplo seria sempre registrar se algum valor foi atualizado por meio de um método definido. Isso não criará um antipadrão e dificilmente será a causa de qualquer problema.
Pode-se dizer que, se você pode abusar facilmente da AOP para criar tantos problemas, é uma má idéia usar tudo. No entanto, qual tecnologia não pode ser abusada? Você pode abusar do encapsulamento de dados, você pode abusar da herança. Praticamente todas as tecnologias de programação úteis podem ser abusadas. Considere uma linguagem de programação tão limitada que contenha apenas recursos que não possam ser abusados; um idioma em que os recursos podem ser usados apenas como inicialmente pretendidos. Essa linguagem seria tão limitada que é discutível se ela pode ser usada para programação no mundo real.