【Singeltonパターン】考え方は単純だが、使いどころが大切なデザインパターン【コード例はRubyとJava】

前書き:Singletonパターンは奥が深い

Singletonパターンは、GoF(Gang of Four)デザインパターンの一つであり、あるクラスのインスタンスが一つしかない状態を保証する方法です。「インスタンスが一つしか無い」という前提を生み出す事で、複数のインスタンスを用いる事によるバグの発生リスクを無くせます(正しく実装できていれば)。

Singletonパターンに則ったクラスである条件は、以下の3点です。

  • publicのコンストラクタを持たず、privateのコンストラクタを持つ。
  • private変数として、自身のクラスインスタンスを持つ。
  • public関数として、自身のクラスインスタンスを返すgetterメソッドを持つ。

Singletonは作り方のシンプルさと裏腹に、使い方を誤ったケースが多いデザインパターンです。そのため、本記事では「Singletonが適さないケース」、「Singletonが適したケース」、「Singletonが適したクラス(機能)例」、「Singeltonの実装例(Ruby、Java)」を説明します。

                           

Singletonパターンが適さないケース

No. 適さないケース 理由
1 多くの状態(filed、メンバ変数)を持つ 状態はグローバル変数と同一なので、その数は0に近い方が良い
2 単体テストの実行順に制約を生む場合 単体テストの作成および実行を困難にしてしまう
3 マルチスレッド環境に導入する場合 Singeltonへのアクセス管理(ロック)にコストが発生してしまう
4 常に決まった値を渡す(or 出力) クラスメソッド(static関数)に置き換えた方が良い

                      

Singletonパターンが適したケース

IBMが定義するSingletonパターンが適したケースは、以下の3項目を全て満たした場合です。正直、私は下記の引用説明ではピンとこなかったので、Singletonを使ったクラス例を調べました(後述しています)。

すべてのアプリケーションは、まったく同一の方法でこのクラスを使用するか? (「まったく」がキーワード)
すべてのアプリケーションは、常にこのクラスの1つのインスタンスのみを必要とするか? (「常に 」と「1つの」がキーワード)
このクラスのクライアントは、自分自身がその一部に含まれているアプリケーションを意識しないべきか?

                       

Singletonパターンが適したクラス例

以下に、Singletonパターンで設計した方が良い可能性のあるクラス(機能)を示します。

  • ロギング
  • キャッシュ管理
  • スレッドプール管理
  • データベース接続ドライバ
  • ソケット制御ドライバ

上記のクラス(機能)を踏まえると、リソース管理にSingletonパターンが適していると考えられます。リソースに対して複数のインスタンスが管理を行えば、状態管理で不整合が生じる可能性があります。この不整合を防止するために、Singletonを用いるのは自然な事だと思います。

                   

Singletonパターンの実装例(Ruby)

Singletonパターンを実装するには、singletonモジュールをClassにMix-inします。singletonモジュールによって、new()メソッドはprivateメソッドとなり、Singleton化されたクラス外部からnew()をコールすれば“private method `new’ called for SingletonClass:Class (NoMethodError)”とエラーが発生します

以下に、実装例(singleton.rb)を示します。インスタンスが生成されるタイミングは、初めてinstance()メソッドをコールした時になります。

実行例は、以下の通りです。

                                               

Singletonパターンの実装例(JavaでEnumを用いた場合)

Enumを利用する理由は、Javaの言語仕様上、Enumがグローバルに唯一のインスタンスとなる事が保証されるためです。Enumは、厳密なSingletonであり、スレッドセーフかつabstractな実装もできます。最も大きなデメリットは、Java言語仕様を知らない人が見ると、不思議なコードと感じてしまう事でしょう。

を踏まえると以下、実装例(Singleton.java、main.java)です。

実行例は、以下の通りです。

                       

参考書籍:Effective Javaとデザインパターン入門

Effective Javaで、「privateのコンストラクタかenum型でシングルトン特性を強制する」という章があり、Enumを用いたトリッキーな方法を初めて知りました。Singletonに関しても知識がなかったため、並行してデザインパターン入門を読みつつ、本記事に書いたような一般的な知識も調査しました。

Javahaオブジェクト指向に関する知見が多いという点では、良い言語ですね。

おすすめ

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です