ClosureとCallBack
クロージャの別名:閉包
簡単といえば、クロージャとは処理をカプセル化し、引数のように渡せるもの
CallBackとはクロージャを利用するもの
C#
// API:System.Predicate<T>
public delegate bool Predicate<T>(T obj)
static class ListUtil
{
public static IList<T> Filter<T>(IList<T> source, Predicate<T> predicate)
{
List<T> ret = new List<T>();
foreach (T item in source)
{
if (predicate(item))
{
ret.Add(item);
}
}
return ret;
}
}
PHP
function foo($arg) {
$var = 1;
$inner = function($innerArg) use($arg, $var){
...
}
//$inner->a = 5; × プロパティを持てない内部クラスに相当
echo $inner(3);
}
★PHPによるCallBack
<?php
class Hepler
{
public static function doAction($callBack)
{
$callBack();
}
}
function callBack()
{
// do something
}
// 利用側
Hepler::doAction('callBack');
?>
★JavaScriptによるCallBack
function doAction(p,callback){
callback();
}
function callback(){
// do something
}
// 利用側
doAction("xxx", callback);
或いは
doAction("xxx", function method(){
// do something
});
JavaScriptのcallbackの注意点
var target = {
name: 'Andy',
getName: function(data){
return data + ':' + this.name;
}
};
var app1 = function(callback){
if(typeof callback === 'function'){
return callback('Hello'); //ここのthisはwindow
}
};
var app2 = function(callback, obj){
if(typeof callback === 'function'){
return callback.call(obj, 'Hello'); //ここのthisはtarget
}
if(typeof callback === 'string'){
return obj[callback]('Hello'); //ここのthisはtarget
}
};
console.log(app1(target.getName)); //Hello:undefined
console.log(app2(target.getName, target)); //Hello:Andy
console.log(app2('getName', target)); //Hello:Andy
JavaScriptのクロージャについて
注意点:メモリリーク
もっと遅い書き方
var msg = "This is test";
window.setTimeout(
function(){
alert(msg);
},
2000);
遅い書き方
window.setTimeout(
function(){
var msg = "This is test";
alert(msg);
},
2000);
速い書き方
function alertMsg(){
var msg = "This is test";
alert(msg);
}
window.setTimeout(alertMsg, 2000);
$(document).ready(function() {
var spans = $("#test span");
for (var i = 0; i < spans.length; i++) {
spans[i].onclick = function() { // ×
alert(i);
};
}
});
var spans = $("#test span");
$(document).ready(function() {
for (var i = 0; i < spans.length; i++) {
(function(num) { // 〇
spans[i].onclick = function() {
alert(num);
}
})(i);
}
});
★CallBackの応用例
1.Ajax
xmlHttp.onreadystatechange = callback
2.SpringのHibernateTemplate
interface CallBack{
public void doCRUD();
}
public class HibernateTemplate {
public void execute(CallBack action){
getConnection();
action.doCRUD();
releaseConnection();
}
public void add(){
execute(new CallBack(){
public void doCRUD(){
// do something
}
});
}
public void delete(){
execute(new CallBack(){
public void doCRUD(){
// do something
}
});
}
public void getConnection(){
// do something
}
public void releaseConnection(){
// do something
}
}
Java
public interface Predicate<T>
{
boolean match(T item);
}
public class ListUtil
{
public static <T> List<T> filter(List<T> source, Predicate<T> predicate)
{
ArrayList<T> ret = new ArrayList<T>();
for (T item : source)
{
if (predicate.match(item))
{
ret.add(item);
}
}
return ret;
}
}
★JavaによるCallBack
サンプル1
public interface CallBack{
void doAction(String str);
}
public class Test{
private CallBack callback;
public void setCallback(CallBack callback){
this.callback = callback;
}
public static void method1(String name, CallBack callback){
callback.doAction(name);
}
public void method2(String name){
if(callback != null){
callback.doAction(name);
}
}
}
// 利用側
Test.method1("Andy", new CallBack(){
public void doAction(String str){
// do something
}
});
Test t = new Test();
t.setCallback(new CallBack(){
public void doAction(String str){
// do something
}
});
t.method2();
サンプル2(内部インターフェース)
public class Zoo {
private String name;
private List<Animal> animalList;
// 重量を合計
public int calculateWeight(){
return calculateTotal(new CallBack(){
public int getAmount(Animal animal) {
return animal.getWeight();
}
});
}
// 足の数を合計
public int calculateLegs(){
return calculateTotal(new CallBack(){
public int getAmount(Animal animal) {
return animal.getLeg();
}
});
}
private interface CallBack {
int getAmount(Animal animal);
}
// 合計処理
private int calculateTotal(CallBack callback){
int total = 0;
for (Animal animal : animalList) {
total += callback.getAmount(animal);
}
return total;
}
// getter/setter
}