En tant que développeur OO , j'ai peut-être du mal à comprendre sa valeur. Quelle valeur ajoutée donnent-ils? Est-ce qu'ils s'insèrent dans un monde OO?
Réponses
Trop de publicités?Vous pouvez la voir comme une généralisation d'une classe.
Votre classe contient un certain état. Il a certaines des variables de membre de ses méthodes peuvent utiliser.
Une fermeture est simplement une façon plus pratique de donner une fonction d'accès aux locaux de l'état.
Plutôt que d'avoir à créer une classe qui sait à propos de la variable que vous souhaitez que la fonction à utiliser, vous pouvez simplement définir la fonction sur la place, elle peut implicitement l'accès à chaque variable qui est actuellement visible.
Lorsque vous définissez un membre de la méthode traditionnelle de la programmation orientée objet du langage, sa fermeture est "tous les membres visibles dans cette classe".
Langues avec "bon" soutien de fermeture simplement généraliser, donc une fonction de la fermeture de "toutes les variables visibles ici". Si "ici" est une classe, alors vous avez une traditionnelle méthode de classe.
Si "ici" est à l'intérieur d'une autre fonction, alors vous avez ce qu'fonctionnelle programmeurs considèrent comme une fermeture. Votre fonction peut maintenant accéder à tout ce qui était visible dans la fonction parente.
Donc, c'est juste une généralisation, le retrait de la bête restriction que "les fonctions ne peuvent être définies à l'intérieur des classes", mais en gardant l'idée que "les fonctions peuvent voir ce que les variables sont visibles à l'endroit où elles sont déclarées".
Les fermetures ne vous donnent aucun pouvoir supplémentaire.
Tout ce que vous pouvez réaliser avec eux, vous pouvez le faire sans eux.
Mais ils sont très utiles pour rendre le code plus clair et lisible. Et comme nous le savons tous, un code court lisible est un code plus facile à déboguer et contenant moins de bogues.
Permettez-moi de vous donner un court exemple d'utilisation possible en Java:
button.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) {
System.out.println("Pressed");
}
});
Serait remplacé (si Java avait des fermetures) par:
button.addActionListener( { System.out.println("Pressed"); } );
Pour moi, le plus grand avantage de fermetures, c'est quand vous écrivez du code qui commence une tâche, laisse la tâche à exécuter, et spécifie ce qui doit se passer lorsque la tâche est terminée. Généralement le code qui s'exécute à la fin de la tâche a besoin d'accéder aux données qui sont disponibles au début, et les fermetures de rendre cela facile.
Par exemple, une utilisation courante en JavaScript est de lancer une requête HTTP. Celui qui commence, il veut sans doute pour contrôler ce qui se passe quand la réponse arrive. Donc, vous allez faire quelque chose comme ceci:
function sendRequest() {
var requestID = "123";
Ext.Ajax.request({
url:'/myUrl'
success: function(response) {
alert("Request " + requestID + " returned");
}
});
}
Parce que du JavaScript fermetures, la "iddemande" variable est capturé à l'intérieur de la réussite de la fonction. Cela montre comment vous pouvez écrire la demande et des fonctions de réponse dans le même lieu, et de partager des variables entre elles. Sans fermeture, vous aurez besoin pour passer en iddemande comme argument, ou créer un objet contenant iddemande et la fonction.
À mon humble avis il vient vers le bas pour être en mesure de capturer des blocs de code et de leur contexte pour être référencé à un certain moment plus tard et exécutée lorsque/si/en tant que de besoin.
Ils peuvent ne pas sembler une grosse affaire, et les fermetures ne sont certainement pas quelque chose que vous besoin de faire les choses sur une base quotidienne, mais ils peuvent rendre le code code beaucoup plus simple et plus propre d'écrire/de gérer.
[edit - exemple de code basé sur le commentaire ci-dessus]
Java:
List<Integer> numbers = ...;
List<Integer> positives = new LinkedList<Integer>();
for (Integer number : integers) {
if (number >= 0) {
positives.add(number);
}
}
Scala (sauter quelques-uns des autres subtilités comme l'inférence de type caractères génériques et donc nous ne sommes qu'à la comparaison de l'effet de la fermeture):
val numbers:List[Int] = ...
val positives:List[Int] = numbers.filter(i:Int => i >= 0)
C'est dommage, les gens n'apprennent plus Smalltalk dans edu; là, les fermetures sont utilisés pour les structures de contrôle, les rappels, la collecte de l'énumération, la gestion des exceptions et plus. Pour un petit exemple, voici une file d'attente de travail action thread de gestion (en Smalltalk):
|actionQueue|
actionQueue := SharedQueue new.
[
[
|a|
a := actionQueue next.
a value.
] loop
] fork.
actionQueue add: [ Stdout show: 1000 factorial ].
et, pour ceux qui ne savent pas lire Smalltalk, même dans la syntaxe JavaScript:
var actionQueue;
actionQueue = new SharedQueue;
function () {
for (;;) {
var a;
a = actionQueue.next();
a();
};
}.fork();
actionQueue.add( function () { Stdout.show( 1000.factorial()); });
(eh bien, comme vous le voyez: la syntaxe d'aide à la lecture du code)
Edit: remarquez comment actionQueue est référencé à partir de l'intérieur des blocs, qui fonctionne même pour la fourche thread-bloc. C'est ce qui fait des fermetures de très facile à utiliser.