最近、ActionScript3.0でコードを書いています。当然、今まで使っていた言語とは様々な仕様上の違いがあるのですが、その中でちょっと困ったのは、コンストラクタにprivate属性を指定できないこと。Singletonパターンなどを実装しようとしてprivateなコンストラクタを宣言すると、コンパイル時に「A constructor can only be declared public.」というエラーが発生してしまいます。
小さなプロジェクトであれば「インスタンス化しないように注意する」ということでもなんとかなりますが、やはりどうしても寝覚めが悪いので、対策を考えてみます。
まずは、毎度お馴染みのGoogle先生によると、どうやら次のようなコードが定石のようです。
package { import flash.errors.IllegalOperationError; public class Singleton { private static var instance:Singleton; private static var internally:Boolean = false; public static function getInstance():Singleton { if (instance == null) { internally = true; instance = new Singleton(); } return instance; } public function Singleton() { if (!internally) { throw new IllegalOperationError( "Should not be instantiated!!"); } internally = false; } public function doSomething():void {} } }
private staticのフラグ属性を持ち、内部でインスタンスを生成する場合はフラグをtrueに設定してコンストラクタを呼び出します。コンストラクタでは、このフラグをチェックし、フラグがtrueでなければエラーをthrowします。
また、ActionScript3.0から可能になった、package外でのクラス宣言を使った方法もありました。
package { import flash.errors.IllegalOperationError; public class Singleton { private static var instance:Singleton; public static function getInstance():Singleton { if (instance == null) { instance = new Singleton(new Internal()); } return instance; } public function Singleton(internally:Internal) { if (internally == null) { throw new IllegalOperationError( "Should not be instantiated!!"); } } public function doSomething():void {} } } class Internal { }
これは、package外に宣言したクラスが、そのファイル内からしか参照できないことを利用しています。Internalクラスのインスタンスが生成できなければ、Singletonクラスのコンストラクタを呼び出すことが出来ず、nullを渡したとしても実行時にエラーがthrowされます。
しかしながら、これらの方法では、コードをコンパイルして実行してみなければ、エラーの存在がわかりません。そこで、こんな方法を考えました。
package { import flash.errors.IllegalOperationError; public class Singleton { private static var instance:SingletonImpl; public static function getInstance():SingletonImpl { if (instance == null) { instance = new SingletonImpl (); } return instance; } } } class SingletonImpl { public function SingletonImpl() { } public function doSomething():void {} }
package外クラスに機能を全て実装し、publicクラスにはstaticメソッドのみを定義します。クラスのユーザーがdoSomethingを呼び出すためにはSingletonImplクラスにアクセスしなければならず、そのためにはSingletonクラスのgetInstanceを呼ぶしかありません。Singletonクラスのインスタンス化をコンパイル時に回避することは不可能なのですが、Singletonクラスがインスタンス化されたとしても、SingletonImplのインスタンスが唯一であることは保たれます。
冒頭にも書いた通り、まだActionScriptを使い始めたばかりなので、何か落とし穴があるのかも知れません。何かコメントがあれば、ご指摘いただければ幸いです。
[…] ActionScript3.0でSingletonパターンを実装する c9日記 -カタヤマンがプログラマチックに今日もコードアシスト [AS3][Flex2]インナークラス しっぽ流デザインパターン講座(F-site講演資料) < […]
[…] 221;データ保存用のstateオブジェクト(連想配列)”の外部クラスVer.です。中身にはシングルトンとかいろいろ小技が仕込まれています。 これにより、Mainクラスおよびそれにぶら下が […]
[…] としたらコンストラクタがpublicじゃないとダメという仕様で、Google先生に聞いたところいろいろやり方があるようで。 ここではいろいろな方法を紹介していた。 http://blog.bitmeister.jp/?p=1624 […]