Quel est cet idiome « Exécuter Around » (ou similaire) j’ai entendu parler ? Pourquoi je pourrais l’utiliser, et Pourquoi utiliserais-je pas à l’utiliser ?
Réponses
Trop de publicités?En gros, c'est le modèle où vous écrivez une méthode pour faire des choses qui sont toujours nécessaire, par exemple, l'allocation des ressources et de nettoyage, et de faire de l'appelant passer en "ce que nous voulons faire avec la ressource". Par exemple:
public interface InputStreamAction
{
void useStream(InputStream stream) throws IOException;
}
// Somewhere else
public void executeWithFile(String filename, InputStreamAction action)
throws IOException
{
InputStream stream = new FileInputStream(filename);
try {
action.useStream(stream);
} finally {
stream.close();
}
}
// Calling it
executeWithFile("filename.txt", new InputStreamAction()
{
public void useStream(InputStream stream) throws IOException
{
// Code to use the stream goes here
}
});
Le code appelant n'a pas besoin de s'inquiéter à propos de l'ouverture, le nettoyage côté - ci seront pris en charge par executeWithFile
.
Franchement, c'est très douloureux en Java, car les fermetures sont tellement verbeux - dans les langues avec une meilleure fermeture de la syntaxe (par exemple, des expressions lambda C#, ou Groovy), cela fait beaucoup plus de sens. (En C# ce cas particulier, est déjà géré avec using
des déclarations, vous l'esprit.)
Bien que "d'affecter et de clean-up" est l'exemple typique étant donné, il y a beaucoup d'autres exemples possibles - la gestion des transactions, de l'exploitation forestière, de l'exécution du code avec plus de privilèges etc. En gros, c'est un peu comme la méthode de modèle de modèle , mais sans héritage.
L'Exécution Autour de langage est utilisé lorsque vous vous trouvez avoir à faire quelque chose comme ceci:
//... chunk of init/preparation code ...
task A
//... chunk of cleanup/finishing code ...
//... chunk of identical init/preparation code ...
task B
//... chunk of identical cleanup/finishing code ...
//... chunk of identical init/preparation code ...
task C
//... chunk of identical cleanup/finishing code ...
//... and so on.
Afin d'éviter de répéter l'ensemble de ce code redondant qui est toujours "autour" de votre réelle des tâches, vous devez créer une classe qui prend soin de lui automatiquement:
//pseudo-code:
class DoTask()
{
do(task T)
{
// .. chunk of prep code
// execute task T
// .. chunk of cleanup code
}
};
DoTask.do(task A)
DoTask.do(task B)
DoTask.do(task C)
Cet idiome se déplace tout de la complexité de code redondant dans un seul endroit, et laisse votre programme principal beaucoup plus lisible (et plus facile à gérer!)
Jetez un oeil à ce post pour un exemple en C#, et cet article pour un exemple C++.
Je vois que vous avez un Java tag ici, donc je vais utiliser Java comme un exemple, même si le modèle n'est pas spécifique à la plateforme.
L'idée est que, parfois, vous disposez d'un code qui implique toujours le même standard avant d'exécuter le code et après l'exécution du code. Un bon exemple est JDBC. Vous avez toujours saisir un de la connexion et de créer un énoncé (ou d'une instruction préparée) avant de lancer le réel de la requête et de traitement de l'ensemble de résultats, et ensuite, vous faites toujours le même standard de nettoyage à la fin--fermeture de la déclaration et de la connexion.
L'idée à exécution-est que c'est mieux si vous pouvez factoriser le code réutilisable. Qui vous permet d'économiser un peu de temps, mais la raison est plus profonde. C'est le don't repeat yourself (SEC) principe ici, de vous isoler du code à un endroit donc si il y a un bug ou vous avez besoin de la changer, ou si vous voulez le comprendre, c'est tous en un seul endroit.
La chose qui est un peu compliqué avec ce genre d'affacturage est que vous avez des références à la fois le "avant" et "après" les parties ont besoin de voir. Dans l'exemple JDBC cela inclut la Connexion et (Préparé)Déclaration. Donc à gérer que vous essentiellement "wrap" votre code cible avec le code réutilisable.
Vous connaissez peut-être certains cas en Java. On est servlet filtres. Une autre est de l'AOP autour de conseils. Troisièmement, les différentes xxxTemplate classes au Printemps. Dans chaque cas, vous avez quelques wrapper objet dans lequel votre "intéressant" (code dire la requête JDBC et de l'ensemble de résultats de traitement) est injecté. L'objet de wrapper est-ce que "avant", invoque les codes intéressants et puis le "après".
Une Exécution Autour de la Méthode est l'endroit où vous passez du code arbitraire à une méthode, qui peut effectuer la configuration et/ou de démontage de code et l'exécution de votre code entre les deux.
Java n'est pas la langue que je préfère pour ce faire. Il est plus élégant de passer une fermeture (ou lambda expression) comme argument. Si les objets sont sans doute équivalent à des fermetures.
Il me semble que la tâche d'Exécution Autour de la Méthode est un peu comme l'Inversion de Contrôle (Dependency Injection) que vous pouvez varier ad hoc, chaque fois que vous appelez la méthode.
Mais il pourrait aussi être interprété comme un exemple de Contrôle de Couplage (le fait de dire une méthode que faire de son argument, littéralement, dans ce cas).
Voir aussi Code sandwichs, qui étudie cette construction à travers de nombreux langages de programmation et vous propose quelques idées intéressantes de research'y.