prototype.js の Class 拡張試案 (Main, Singleton etc.)

Update [20060301]: id:reinyannyan:20051118:p1 の末尾に修正点を追記しましたのでご覧下さい。


id:reinyannyan:20051015:1129388215 において、prototype.js の Object.prototype 汚染の問題を紹介させて頂きました。

その文脈の中で、(コーディングの便のため)クラス定義の場合に限り、従来の extend メソッドが使えないか、ということを考えました。

今回はそのアイディアを押し広げて、全面的に Class オブジェクトを書き換えてみたものをお見せしたいと思います。

abstract と concrete

Class::create の拡張です。

var Class =
{
    abstract: function ()
    {
	return function ()
	{
	    Object.extend(this, Class.Methods);
	};
    },
    concrete: function ()
    {
	return function ()
	{
	    Object.extend(this, Class.Methods);
	    this.initialize.apply(this, arguments);
	};
    },
    ...
};
Class.create = Class.concrete;

これまで空関数を使用して定義していた抽象クラスを Class.abstract() として定義できるようにします。この関係で、create にあたるものを、意味論的一貫性のため、concrete として定義しております。

Class.Methods の中身はこのようなものです。

Class.Methods =
{
    clone: function ()
    {
	return Object.clone(this);
    },
    extend: function (object)
    {
	return Object.extend(this, object);
    }
};

Object::clone については id:reinyannyan:20051017:1129555088 を参照してください。

Main

C 等の main にあたる関数をクラスとして定義するためのものです(ブラウザで実行されるスクリプトを想定しています)。

var Class =
...
    main: function ()
    {
	return function ()
	{
	    window.onload = this.main.bind(this);
	    window.onunload = this.unmain.bind(this);
	};
    },
    ...

一般クラスの initialize に代わり、main と unmain メソッドの定義を義務付けます。

利用サンプル:

var Main = Class.main();
Main.prototype =
{
    main: function ()
    {
	// main code
    },
    unmain: function ()
    {
	// cleanup code here
    }
};
new Main; // program starts

new するとプログラム開始です。ページのロードと同時に main が実行されます。unmain は、window の unload 時に実行すべきクリーンアップ・コードです。ネーミングはあまり一般的ではないと思いますが、load と unload との対称ということで。

unmain は要らないという場合は、if を付けるか、

	window.onunload = (this.unmain || Prototype.emptyFunction).bind(this);

のようにしても良いかと思います。

Singleton

id:reinyannyan:20051015:1129356763 の改良版(?)です。

var Class =
...
    singleton: function ()
    {
	return Object.extend({ instance: null }, Class.Methods);
    }

利用サンプル:

var Singleton = Class.singleton().extend(
{
    getInstance: function ()
    {
	if (!this.instance)
	{
	    // constructor
	    var singleton = Class.create();
	    singleton.prototype =
	    {
		...
	    };
	    this.instance = new singleton;
	}
	return this.instance;
    }
});

メソッドを作るほどでもないような気もしますね…。まぁおまけということで。