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

}