Pourquoi "vs"? Ce n'est pas "vs". Vous pouvez utiliser la programmation orientée aspect en combinaison avec la programmation fonctionnelle, mais également en combinaison avec la programmation orientée objet. Ce n'est pas "vs", c'est "Programmation Orientée Aspect avec Programmation Orientée Objet".
Pour moi, l'AOP est une sorte de "méta-programmation". Tout ce que fait AOP pourrait également être fait sans lui en ajoutant simplement plus de code. AOP vous évite simplement d'écrire ce code.
Wikipedia a l'un des meilleurs exemples de cette méta-programmation. Supposons que vous ayez une classe graphique avec de nombreuses méthodes "set ... ()". Après chaque méthode définie, les données des graphiques ont changé, ainsi les graphiques ont changé et donc les graphiques doivent être mis à jour à l'écran. Supposons que pour repeindre les graphiques, vous devez appeler "Display.update ()". L'approche classique consiste à résoudre ce problème en ajoutant plus de code . À la fin de chaque méthode définie, vous écrivez
void set...(...) {
:
:
Display.update();
}
Si vous avez 3 méthodes set, ce n'est pas un problème. Si vous en avez 200 (hypothétique), cela devient vraiment pénible d'ajouter cela partout. De plus, chaque fois que vous ajoutez une nouvelle méthode set, vous devez vous assurer de ne pas oublier de l'ajouter à la fin, sinon vous venez de créer un bogue.
AOP résout cela sans ajouter des tonnes de code, à la place, vous ajoutez un aspect:
after() : set() {
Display.update();
}
Et c'est tout! Au lieu d'écrire le code de mise à jour vous-même, vous dites simplement au système qu'après avoir atteint un pointcut set (), il doit exécuter ce code et il l'exécutera. Pas besoin de mettre à jour 200 méthodes, pas besoin de s'assurer de ne pas oublier d'ajouter ce code sur une nouvelle méthode set. De plus, vous avez juste besoin d'un point:
pointcut set() : execution(* set*(*) ) && this(MyGraphicsClass) && within(com.company.*);
Qu'est-ce que ça veut dire? Cela signifie que si une méthode est nommée "set *" (* signifie que n'importe quel nom peut suivre après set), indépendamment de ce que la méthode retourne (premier astérisque) ou des paramètres qu'elle prend (troisième astérisque) et c'est une méthode de MyGraphicsClass et ceci classe fait partie du package "com.company. *", il s'agit alors d'un pointcut set (). Et notre premier code dit " après avoir exécuté une méthode qui est un point de consigne, exécutez le code suivant".
Voyez comment AOP résout élégamment le problème ici? En fait, tout ce qui est décrit ici peut être fait au moment de la compilation. Un préprocesseur AOP peut simplement modifier votre source (par exemple en ajoutant Display.update () à la fin de chaque méthode set-pointcut) avant même de compiler la classe elle-même.
Cependant, cet exemple montre également l'un des gros inconvénients d'AOP. AOP fait en fait quelque chose que de nombreux programmeurs considèrent comme un " anti-modèle ". Le motif exact est appelé " Action à distance ".
L'action à distance est un anti-modèle (une erreur commune reconnue) dans lequel le comportement dans une partie d'un programme varie énormément en fonction des opérations difficiles ou impossibles à identifier dans une autre partie du programme.
En tant que débutant dans un projet, je pourrais simplement lire le code de n'importe quelle méthode set et le considérer comme cassé, car il ne semble pas mettre à jour l'affichage. Je ne vois pas en regardant simplement le code d'une méthode set, qu'après son exécution, un autre code sera "magiquement" exécuté pour mettre à jour l'affichage. Je considère cela comme un sérieux inconvénient! En apportant des modifications à une méthode, des bogues étranges peuvent être introduits. Comprendre davantage le flux de code où certaines choses semblent fonctionner correctement, mais ne sont pas évidentes (comme je l'ai dit, elles fonctionnent comme par magie ... d'une manière ou d'une autre), est vraiment difficile.
Mettre à jour
Juste pour clarifier cela: Certaines personnes pourraient avoir l'impression que je dis que l'AOP est quelque chose de mauvais et ne devrait pas être utilisé. Ce n'est pas ce que je dis! AOP est en fait une excellente fonctionnalité. Je dis juste "Utilisez-le soigneusement". AOP ne causera des problèmes que si vous mélangez du code normal et AOP pour le même aspect . Dans l'exemple ci-dessus, nous avons l'aspect de mettre à jour les valeurs d'un objet graphique et de peindre l'objet mis à jour. Il s'agit en fait d'un seul aspect. Le codage de la moitié en code normal et de l'autre moitié en tant qu'aspect est ce qui ajoute le problème.
Si vous utilisez AOP pour un aspect complètement différent, par exemple pour la journalisation, vous ne rencontrerez pas le problème anti-modèle. Dans ce cas, un débutant dans le projet pourrait se demander "D'où viennent tous ces messages de journal? Je ne vois aucune sortie de journal dans le code", mais ce n'est pas un gros problème. Les modifications qu'il apporte à la logique du programme ne briseront guère la fonction de journalisation et les modifications apportées à la fonction de journal ne briseront guère la logique de son programme - ces aspects sont totalement séparés. L'utilisation d'AOP pour la journalisation a l'avantage que votre code de programme peut se concentrer pleinement sur ce qu'il doit faire et vous pouvez toujours avoir une journalisation sophistiquée, sans que votre code soit encombré par des centaines de messages de journal partout. De plus, lorsqu'un nouveau code est introduit, les messages de journal apparaissent comme par magie au bon moment avec le bon contenu.
Donc, une bonne utilisation d'AOP dans mon exemple serait de toujours se connecter si une valeur a été mise à jour via une méthode set. Cela ne créera pas d'anti-motif et ne sera presque jamais la cause d'un problème.
On pourrait dire que si vous pouvez facilement abuser d'AOP pour créer autant de problèmes, c'est une mauvaise idée de tout utiliser. Mais quelle technologie ne peut pas être utilisée abusivement? Vous pouvez abuser de l'encapsulation des données, vous pouvez abuser de l'héritage. Presque toutes les technologies de programmation utiles peuvent être utilisées à mauvais escient. Considérez un langage de programmation si limité qu'il ne contient que des fonctionnalités qui ne peuvent pas être utilisées abusivement; un langage où les fonctionnalités ne peuvent être utilisées que comme elles étaient initialement destinées à être utilisées. Un tel langage serait si limité qu'il est discutable s'il peut même être utilisé pour une programmation du monde réel.