ActionScript3.0におけるSingletonパターン

Singletonパターンとは、クラスのインスタンスが一つしか生成されないことを保証するデザインパターンの一種です。ActionScript3.0では、コンストラクタにアクセス制御の属性としてprivateを指定することができないため、Singletonパターンを実装するためには、ちょっとした工夫が必要になります。AS3におけるSingletonパターンの実装方法も色々と存在していますが、その中で代表的なものを見てみます。

privateクラスを利用した実装方法

ActionScript3.0では、クラスに対してもprivate属性を指定することができません。しかし、package{}の外にクラスの定義を記述することで事実上のprivateクラスとなります。このprivateクラスをコンストラクタの引数に使用することでSingletonパターンを実装することができます。

ActionScript3.0

package {
  public class Singleton1 {
    private static var _instance:Singleton1;
    public function Singleton1(privateClass:PrivateClass) {
      trace("Singleton1's constructor");
    }
    public static function getInstance():Singleton1 {
      if (!_instance) {
        _instance = new Singleton1(new PrivateClass);
      }
      return _instance;
    }
  }
}
class PrivateClass {
}

下記コードをテストすると、Singleton1クラスのコンストラクタのtrace文は一度しか出力されません。また、singleton1Aとsingleton1Bを==比較演算子で比べるとtrueが出力され、同じインスタンスを参照していることがわかります。

また、1行目のコメントアウトを解除し実行するとコンパイルエラーとなります。これは、package{}の外側に記述したPrivateClassは、Singleton1.as以外からは参照することが不可能なため、事実上のprivateクラスとなっているからです。

ActionScript3.0

//var singleton1:Singleton1 = new Singleton1(new PrivateClass);
var singleton1A:Singleton1 = Singleton1.getInstance();
var singleton1B:Singleton1 = Singleton1.getInstance();
trace(singleton1A, singleton1B)
trace(singleton1A == singleton1B);

/* 出力
Singleton1's constructor
[object Singleton1] [object Singleton1]
true
*/

なお、こういったprivateクラスの使用は、ActionScript3.0のクラスファイルの特性上、第3者にとって解りづらくなりがちなので注意が必要です。

private静的(static)プロパティのフラグを利用した実装方法

次は、private静的(static)プロパティのフラグを利用した実装方法を見てみます。まず、クラス内部からの呼び出しであるかを示すフラグとして、private静的プロパティをBoolean型で宣言し、初期値としてfalseを代入しておきます。getInstance()が呼ばれた際に、インスタンスが生成されていない場合は、このフラグをtrueにしてコンストラクタを呼び出します。

ActionScript3.0

package {
  import flash.errors.IllegalOperationError;
  public class Singleton2 {
    private static var _instance:Singleton2;
    private static var _isInternalAccess:Boolean = false;
    public function Singleton2() {
      trace("Singleton2's constructor");
      if (_isInternalAccess) {
        _isInternalAccess = false;
      } else {
        throw new IllegalOperationError("Please call \"Singleton2.getInstance()\" to get the instance.");
      }
    }
    public static function getInstance():Singleton2 {
      if(!Singleton2._instance) {
        _isInternalAccess = true;
        _instance = new Singleton2();
      }
      return _instance;
    }
  }
}

下記コードを実行するとSingleton2クラスのコンストラクタのtrace文は一度しか出力されず、またsingleton2Aとsingleton2Bを==比較演算子で比べたtraceもtrueが出力され、同じインスタンスを参照していることがわかります。1行目のコメントアウトを解除し実行すると内部呼び出しのフラグがfalseであるため、IllegalOperationErrorがthrowされます。

ActionScript3.0

//var singleton2:Singleton2 = new Singleton2();
var singleton2A:Singleton2 = Singleton2.getInstance();
var singleton2B:Singleton2 = Singleton2.getInstance();
trace(singleton2A, singleton2B)
trace(singleton2A == singleton2B);

/* 出力
Singleton2's constructor
[object Singleton2] [object Singleton2]
true
*/

インスタンス格納用プロパティ宣言時にコンストラクタを呼ぶ実装方法

Singletonパターンの特徴として、必ずstaticプロパティに自身のインスタンスを格納します。次の例は、インスタンス格納用プロパティ宣言時にコンストラクタを呼ぶ方法です。クラスの初期化時にインスタンスが作成されるので、以降に外部からコンストラクタが呼ばれた場合は、IllegalOperationErrorがthrowされます。

ActionScript3.0

package {
  import flash.errors.IllegalOperationError;
  public class Singleton3 {
    private static var _instance:Singleton3 = new Singleton3();
    public function Singleton3() {
      if (_instance) {
        throw new IllegalOperationError("Please call \"Singleton3.getInstance()\" to get the instance.");
      }
      trace("Singleton3's constructor");
    }
    public static function getInstance():Singleton3 {
      return _instance;
    }
  }
}

Singleton3クラスのインスタンスは、クラスの初期化時に一度だけ生成され、そのインスタンスがgetInstance()により返されるので、下記コードを実行すると、singleton3Aとsingleton3Bの比較演算子はtrueが出力され、同じインスタンスを参照していることが確認できます。1行目のコメントアウトを解除し、コンストラクタを実行するとIllegalOperationErrorがthrowされます。

ActionScript3.0

//var singleton3:Singleton3 = new Singleton3();
var singleton3A:Singleton3 = Singleton3.getInstance();
var singleton3B:Singleton3 = Singleton3.getInstance();
trace(singleton3A, singleton3B)
trace(singleton3A == singleton3B);

/* 出力
Singleton3's constructor
[object Singleton3] [object Singleton3]
true
*/

以上、ActionScript3.0におけるSingletonパターンの実装方法を見てきましたが、Singletonパターンはstaticメソッドにより、どこからでもインスタンスを取得できるので非常に使い勝手がよいです。また、インスタンスは唯一の存在であることが保証されるので、複数人で作業する場合も安心して使用できます。

Singletonパターンのようなデザインパターンは、先人の知恵の結集とも言えるので、効率的なプログラミングをするために、一冊参考書でも買って勉強したいなと思う今日この頃です。