2013年5月17日金曜日

design patterns – Singleton


シングルトン

シングルトンパターンは、オブジェクトのインスタンスが必ず1つしか作られないようにしたい場合に使用します。従来のオブジェクト指向プログラミング言語では、静的なプロパティとメソッド、および動的なプロパティとメソッドの両方が存在するクラスが関係するため、シングルトン作成の概念は少々複雑であり、理解しづらいものでした。しかし、本稿で取り上げるのはJavaScriptであり、これは厳密なクラスを持たない動的な言語であるため、JavaScriptのシングルトンは非常にシンプルです。

シングルトンを必要とする理由

実装の詳細を解説する前に、シングルトンパターンをアプリケーションで使用すると便利な理由を説明します。オブジェクトのインスタンスを確実に1つに制限できるということは、非常に実用的です。サーバー側言語では、データベース接続の処理にシングルトンを使用することもできます。要求ごとにデータベース接続を繰り返し作成するのは、リソースの無駄でしかないからです。同様に、フロントエンドJavaScriptでは、すべてのAJAX要求を処理するオブジェクトをシングルトンにすることもできます。シングルトン化のルールは、まったく同じ機能を持つ新規インスタンスをいくつも作成するのならシングルトン化する、というシンプルなものです。
とはいえ、シングルトン化の理由はこれだけではありません。少なくともJavaScriptでは、シングルトンを使用することで名前空間のオブジェクトと関数を整理できるので、グローバル名前空間が無秩序になりません。グローバル名前空間が乱雑になるのは、サードパーティコードを使用している場合は特に、避けたい事態です。名前空間の定義にシングルトンを使用することを、モジュールデザインパターンとも言います。

シングルトンの例

シングルトンの作成にあたり実際に必要な作業は、オブジェクトリテラルの作成だけです。
var Singleton = { prop: 1, another_prop: 'value', method: function() {…}, another_method: function() {…} };
非公開のプロパティとメソッドを持つシングルトンを作成することもできますが、その場合はクロージャおよび自己実行型匿名関数を使用するため、作業が少し複雑になります。関数内では、いくつかのローカル関数と変数が宣言されます。次に、オブジェクトリテラルを作成して返します。このリテラルには、より大きな関数スコープ内で宣言した変数と関数を参照するメソッドをいくつか含みます。関数宣言の直後に()を挿入しておくと、外部関数が直ちに実行され、返されたオブジェクトリテラルが変数に割り当てられます。この説明がわかりづらいようでしたら、次のコードに目を通してください。説明は、コードの後に続きます。
var Singleton = (function() { var private_property = 0, private_method = function () { console.log('This is private'); } return { prop: 1, another_prop: 'value', method: function() { private_method(); return private_property; }, another_method: function() {…} } }());
関数内で先頭にvarを付けて宣言されている変数は、その関数内からのみアクセス可能です。さらに、アクセスできるのはその関数内で宣言されている関数群(例えば、オブジェクトリテラル内の関数群など)のみです。returnステートメントにより、外部関数の自己実行後にシングルトンに割り当てられるオブジェクトリテラルが返されます。

シングルトンを使用した名前空間の定義

JavaScriptでは、名前空間を定義するには、オブジェクトを別のオブジェクトのプロパティとして追加します。つまり、1層以上の階層構造になります。これはコードを論理セクションごとに分類する場合に便利です。YUI JavaScriptライブラリには名前空間に多数の階層が含まれ、少々過剰な感がありますが、一般には名前空間の入れ子構造は2~3階層以内に抑えることがベストプラクティスと考えられています。次のコードは、名前空間の定義の例です。
var Namespace = { Util: { util_method1: function() {…}, util_method2: function() {…} }, Ajax: { ajax_method: function() {…} }, some_method: function() {…} }; // Here's what it looks like when it's used Namespace.Util.util_method1(); Namespace.Ajax.ajax_method(); Namespace.some_method();
前述のとおり、名前空間の定義を使用することで、グローバル変数の数を最小限に抑えることができます。それどころか、もしその方がよければ、アプリケーション全体をappという名前のシングルトンオブジェクト名前空間にアタッチすることもできます。シングルトンデザインパターンおよび名前空間の定義での応用についてもっと知りたい場合は、筆者の個人ブログの「JavaScript Design Patterns: Singleton」に説明がありますので、ぜひご覧ください。

0 件のコメント: