日記帳

日記です。

委譲

ECMAScript のプロトタイプチェインでの継承は基本的に単一継承なので割とよく委譲を使うことになると思います.もちろんプロトタイプチェインによる継承それ自体も委譲なわけですけど…

委譲といえば Ruby の Forwardable.rb*1 が便利なのでとりあえず ECMAScript 版を作ってみました.

Object.prototype.delegator = function(accessor, methodName, aliasName)
{
	if(!aliasName) aliasName = methodName;
	this[aliasName] = function(){
		this[accessor][methodName].apply(this[accessor], arguments);
	}
}

Object.prototype.delegators = function(accessor)
{
	for (var i = 1;i < arguments.length;i++)
	{
		this.delegator(accessor, arguments[i]);
	}
}

エラー処理が全くない潔いコード(?)です.委譲先のオブジェクトやメソッドが無い場合,実行時に何か例外が飛ぶでしょう(たぶん).

obj.delegator("messenger", "printMessage", "print");

上のようにすれば obj.messenger に入っているオブジェクトの printMessage() メソッドに処理を委譲するメソッドが obj.print に作られます.

以下使い方.

// test Object#delegator()
var helloObj = new Object();
helloObj.printMessage = function() { alert("Hello, world") }
var byeObj = new Object();
byeObj.printMessage = function() { alert("Goodbye, world") }

var obj = new Object();
obj.delegator("messenger", "printMessage", "print");

obj.messenger = helloObj;
obj.print();     // "Hello, world"

obj.messenger = byeObj; // change delegation object
obj.print();     // "Goodbye, world"

Object#delegators() は複数のメソッドをまとめて委譲できます.その代わり定義されるメソッド名は指定できません.委譲先のメソッドと同じ名前のメソッドとなります.

// test Object#delegators()
var messenger = new Object();
messenger.hello = function() { alert("Hello!") }
messenger.thanks = function() { alert("Thanks!") }
messenger.bye = function() { alert("Goodbye!") }

var messenger_ja = new Object();
messenger_ja.hello = function() { alert("こんにちは!") }
messenger_ja.thanks = function() { alert("ありがとう!") }
messenger_ja.bye = function() { alert("さようなら!") }

var obj = new Object()
obj.delegators("messenger", "hello", "bye", "thanks")

obj.messenger = messenger
obj.hello();
obj.thanks();
obj.bye();

// change delegation object
obj.messenger = messenger_ja
obj.hello();
obj.thanks();
obj.bye();

まぁ地味に便利ですねぇ.