デザインパターン > シングルトン(Singleton)

シングルトン(Singleton) - GoF

Singletonパターンはあるクラスのインスタンスが1つであるように制限する為のデザインパターン

「インスタンスが個別に”状態”を持たない場合で、無駄なインスタンス生成を避けたい場合」や、逆に「ある単一のインスタンスの状態を操作、参照したい場合」に有効。
例えば、インスタンス生成が必要な Utilクラスを、ある処理内で複数回使用する時に、無駄なインスタンス生成を避けるのに有効である。

◆Singletonでない処理

 /* メイン処理クラス //
 public Class NormalClass {
  public static void main(String[] args) {

       int a = 10;
       int b = 5;

       NormalUtil util1 = new NormalUtil();
       System.Out.Println(util1.addition(a, b));

       NormalUtil util2 = new NormalUtil()
       System.Out.Println(util2.subtraction(a, b));

       NormalUtil util3 = new NormalUtil()
       System.Out.Println(util3.multiplication(a, b));
   }
 }

 /* 演算用ユーティリティクラス */
 public Class NormalUtil{

  public int addition(int a , int b) {
       return a + b;
   }

  public int subtraction(int a , int b) {
       return a - b;
   }

  public int multiplication(int a , int b) {
       return a * b;
   }
 }

 上記の例では、NormalUtilを使用しているが、同じNormalUtilのインスタンス生成を3度も行っている。
 うち2回は必要のないインスタンス生成である。
 (上記のUtilクラスだと、staticメソッドにすれば、インスタンスを生成する必要すらないのだが、説明の為、あえてインスタンス生成が必要なメソッドにしている。)

 この処理を、Singleton にすると下記のようになる。

◆Singletonな処理

 /* メイン処理クラス */
 public Class NormalClass {

  public static void main(String[] args) {

       int a = 10;
       int b = 5;

       SingletonUtil util1 = SingletonUtil.getInstance()
       System.Out.Println(util1.addition(a, b));

       SingletonUtil util2 = SingletonUtil.getInstance()
       System.Out.Println(util2.subtraction(a, b));

       SingletonUtil util3 = SingletonUtil.getInstance()
       System.Out.Println(util3.multiplication(a, b));
   }
 }

 /* 演算用ユーティリティクラス */
 public Class SingletonUtil{

   /* インスタンスを格納する変数(privateなので外部からの設定は不可) */
   private static SingletonUtil instance = null;

   /* コンストラクタ(外部からのインスタンス生成を禁止する為 protected にする) */
  protected SingletonUtil() {
   }

   /* 単一のインスタンスを取得する為のメソッド */
  public static SingletonUtil getInstance() {
       if (instance == null) {
           instance = new SingletonUtil();
       }
       return instance;
   }

  public int addition(int a , int b) {
       return a + b;
   }

   ・
   ・

 }

 上記のように Singleton にする事によって、確実に無駄なインスタンス生成が行われないように制限をかける事ができる。
 ※実際の開発時には、フレームやDIコンテナの内部でSingletonパターンが使用されている事が多く、ビジネスロジックの実装時に利用する機会は少ないと思われる。

 ただし、上記のコードにマルチスレッドに対応していない
 ※マルチスレッド環境下では、SingletonUtil を唯一のインスタンスとして生成できない。(複数のインスタンスが生成される可能性がある。)

 これを解決する(マルチスレッドに対応する)には、SingletonUtil を以下のように変更する。

 /* 演算用ユーティリティクラス */
 public Class SingletonUtil{

   private static class InstanceHolder {
       public static SingletonUtil instance = new SingletonUtil();
   }

   /* コンストラクタ(外部からのインスタンス生成を禁止する) */
   private SingletonUtil() {}

   /* 単一のインスタンスを取得する為のメソッド */
  public static SingletonUtil getInstance() {
       return InstanceHolder.instance;
   }

   ・
   ・
 }

 上記は Initialize-On-Demand Holder というイディオムで、マルティスレッド環境でシングルトンなインスタンスを安全 かつ シンプルに生成する。
 この手法は、インスタンスが必要になった時点で生成を行う遅延初期化を実現するとともに、double-checked locking 問題などを解決する。


トップ   差分 バックアップ リロード   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2009-06-11 (木) 00:48:51 (4491d)