2007年11月18日日曜日

クロージャと Privileged メソッド

昨日の クロージャの続きです。
OOP な JavaScript では Public メソッド, Private メソッド, Privileged メソッド を定義できますが、クロージャを用いることにより Privileged メソッド が実現できます。
これらのメソッドについて順に見ていくことにします。

Public メソッド

まず Public メソッド を見てみます。オブジェクトのプロパティは、全てが Public で、これらはどんな関数からもアクセスすることができます。
// 神様のコンストラクタ
function God (name, feature) {
this.name = name;
this.feature = feature;
}

// 神様プロトタイプを上書き
God.prototype.getName = function(){
return this.name;
}
God.prototype.getFeature = function(){
return this.feature;
}

// 神様をインスタンス化して大黒天を生成
var god = new God('Daikokuten', 'Syokuji');

// Public メソッド呼出し
alert(god.getName());
///// Daikokuten
オブジェクトにプロパティを追加するには、上記のように、
  • コンストラクタで this キーワードにより追加する
  • プロトタイププロパティで定義する
の 2 通りあります。

プロパティ及び Public メソッドはいつでも追加可能です。
例えば god オブジェクトに年齢プロパティと年齢を取得する Public メソッドを追加しようと思ったら、次のように実現できます。
// 年齢プロパティを追加
god.age = 2000;

// 年齢取得用 Public メソッドを追加
god.getAge = function (){alert(this.age)};

god.getAge();
/////2000

他の神様オブジェクトにも年齢プロパティと年齢を取得する Public メソッドを追加したい場合には、次のように God の prototype プロパティを上書きする方法を取ります。
// God の prototype プロパティを上書き
God.prototype.age = '';
God.prototype.getAge = function(){alert(this.age)};

// age プロパティに代入
god.age = 2000;

// Puclic メソッド呼出し
god.getAge();
/////2000

Private メソッド

次に Private メソッド を見てみます。
// 神様のコンストラクタ
function God (name, feature) {
/**
* 名前を表示する。
* var _getName = function(){....} と同じ
* @access private
*/
function _getName(){
alert(name);
}

// 渡された引数を保存
var name = name;
var feature = feature;

var self = this;

// 名前を表示する関数を実行
_getName();
}

// Public メソッドも定義する
function _getName(){ alert('uso')};

var god = new God('Daikokuten', 'Syokuji');
///// Daikokuten

// Private メソッドにはアクセスできない
_getName();
///// uso
上の例の場合、外部から関数内の var で定義された変数にアクセスすることができず、期待する値と異なる値が返ってくることが分かります。
また、name, age プロパティは定義されておらず、外部からアクセスできないことが分かります。

Privileged メソッド

作成時にしか名前を教えてもらえないのは不便なので、上記を改良して、3 回までなら神様の名前を教えてもらえる関数を作ってみます。
この場合、name をプロパティとして定義せず、限定的に公開するメソッド (Privileged メソッド) を使って以下のように実現することができます。
// 神様のコンストラクタ
function God (name, feature) {
/**
* 制限回数以内かを返却する
* @access private
*/
function _getPrev() {
if (allowed > 0) {
allowed--;
return true;
}
return false;
}

// 渡された引数を保存
var name = name;
var feature = feature;

// 名前を教えることを許可する回数
var allowed = 3;
var self = this;

// Privileged メソッド
this.getName = function (){
return getPrev()? name: 'もう教えません。';
};
}

var god = new God('Daikokuten', 'Syokuji');

alert(god.getName());
///// Daikokuten

alert(god.getName());
///// Daikokuten;

alert(god.getName());
///// Daikokuten;

// 3 回目移行は教えてもらえない
alert(god.getName());
///// もう教えません。
上記のように Privileged メソッドは、クロージャを使い実現されます。

まとめ

以上からPrivileged メソッドの特徴は次のようになります。
  • オブジェクト生成時に作成される
  • プライベート変数とプライベートメソッドにアクセスできる
  • パブリックメソッドなので、削除したり置き換えたりすることができる
  • 改竄したり、隠蔽しているものを無理に明け渡させることはできない