Design patterns
シングルトン
サーチ…
備考
シングルトンのデザインパターンは、「 アンチパターン 」と見なされることがあります。これはいくつかの問題があるという事実のためです。あなたがそれを使用することが適切であると思うならば、自分で決めなければなりません。このトピックは、StackOverflowで何度も議論されています。
参照: http : //stackoverflow.com/questions/137975/what-is-so-bad-about-singletons
シングルトン(C#)
シングルトンは、オブジェクトのインスタンスが1つしか作成されないようにするために使用されます。シングルトンは、自身のインスタンスを1つだけ作成することができます。つまり、作成を制御します。シングルトンはGang of Fourデザインパターンの1つであり、 創造的なパターンです。
スレッドセーフなシングルトンパターン
public sealed class Singleton
{
private static Singleton _instance;
private static object _lock = new object();
private Singleton()
{
}
public static Singleton GetSingleton()
{
if (_instance == null)
{
CreateSingleton();
}
return _instance;
}
private static void CreateSingleton()
{
lock (_lock )
{
if (_instance == null)
{
_instance = new Singleton();
}
}
}
}
Jon Skeetは、スレッドセーフなシングルトンに対して、以下の実装を提供しています。
public sealed class Singleton
{
private static readonly Lazy<Singleton> lazy =
new Lazy<Singleton>(() => new Singleton());
public static Singleton Instance { get { return lazy.Value; } }
private Singleton()
{
}
}
シングルトン(Java)
JavaのシングルトンはC#と非常によく似ています。両方の言語がオブジェクト指向であるためです。以下は、プログラムの存続期間中にオブジェクトの1つのバージョンのみが生存可能なシングルトンクラスの例です(プログラムは1つのスレッドで動作すると仮定します)
public class SingletonExample {
private SingletonExample() { }
private static SingletonExample _instance;
public static SingletonExample getInstance() {
if (_instance == null) {
_instance = new SingletonExample();
}
return _instance;
}
}
そのプログラムのスレッドセーフバージョンです:
public class SingletonThreadSafeExample {
private SingletonThreadSafeExample () { }
private static volatile SingletonThreadSafeExample _instance;
public static SingletonThreadSafeExample getInstance() {
if (_instance == null) {
createInstance();
}
return _instance;
}
private static void createInstance() {
synchronized(SingletonThreadSafeExample.class) {
if (_instance == null) {
_instance = new SingletonThreadSafeExample();
}
}
}
}
Javaには、 ThreadLocal
というオブジェクトもありますThreadLocal
、スレッド単位でオブジェクトのインスタンスを1つ作成します。これは、各スレッドが独自のバージョンのオブジェクトを必要とするアプリケーション
public class SingletonThreadLocalExample {
private SingletonThreadLocalExample () { }
private static ThreadLocal<SingletonThreadLocalExample> _instance = new ThreadLocal<SingletonThreadLocalExample>();
public static SingletonThreadLocalExample getInstance() {
if (_instance.get() == null) {
_instance.set(new SingletonThreadLocalExample());
}
return _instance.get();
}
}
以下は、 enum
(単一の要素のみを含む)を持つシングルトン実装です:
public enum SingletonEnum {
INSTANCE;
// fields, methods
}
Enumクラスの実装は、各要素が存在するインスタンスが1つだけ存在することを保証します。
ビル・プー・シングルトン・パターン
Bill Pugh Singleton Patternは、同期を必要としないため、Singletonクラスで最も広く使用されているアプローチです
public class SingletonExample {
private SingletonExample(){}
private static class SingletonHolder{
private static final SingletonExample INSTANCE = new SingletonExample();
}
public static SingletonExample getInstance(){
return SingletonHolder.INSTANCE;
}
}
プライベート内部静的クラスを使用すると、ホルダーは誰かがgetInstanceメソッドを呼び出すまでメモリにロードされません。 Bill Pughソリューションはスレッドセーフであり、同期は必要ありません。
Singletonsのトピックには、Javaのドキュメンテーションタグの下に、Javaのシングルトンの例がいくつかあります。
シングルトン(C ++)
Wikiによると :ソフトウェア工学では、シングルトンパターンはクラスのインスタンス化を1つのオブジェクトに限定する設計パターンです。
これは、システム全体のアクションを調整するために厳密に1つのオブジェクトを作成するために必要です。
class Singleton
{
// Private constructor so it can not be arbitrarily created.
Singleton()
{}
// Disable the copy and move
Singleton(Singleton const&) = delete;
Singleton& operator=(Singleton const&) = delete;
public:
// Get the only instance
static Singleton& instance()
{
// Use static member.
// Lazily created on first call to instance in thread safe way (after C++ 11)
// Guaranteed to be correctly destroyed on normal application exit.
static Singleton _instance;
// Return a reference to the static member.
return _instance;
}
};
JavaでのLazy Singletonの実用的な例
シングルトンパターンの実際の使用例
クライアント/サーバーアプリケーションを開発する場合、クライアント接続のライフサイクルを管理するConnectionManager
単一インスタンスが必要です。
ConnectionManagerの基本API:
registerConnection
:既存の接続リストに新しい接続を追加する
closeConnection
:クライアントまたはサーバーによってトリガーされたイベントから接続を閉じる
broadcastMessage
:購読しているすべてのクライアント接続にメッセージを送信する必要があります。
サンプルが非常に長くなるので、私はソースコードの完全な実装を提供していません。高レベルでは、コードは次のようになります。
import java.util.*;
import java.net.*;
/* Lazy Singleton - Thread Safe Singleton without synchronization and volatile constructs */
final class LazyConnectionManager {
private Map<String,Connection> connections = new HashMap<String,Connection>();
private LazyConnectionManager() {}
public static LazyConnectionManager getInstance() {
return LazyHolder.INSTANCE;
}
private static class LazyHolder {
private static final LazyConnectionManager INSTANCE = new LazyConnectionManager();
}
/* Make sure that De-Serailzation does not create a new instance */
private Object readResolve() {
return LazyHolder.INSTANCE;
}
public void registerConnection(Connection connection){
/* Add new connection to list of existing connection */
connections.put(connection.getConnectionId(),connection);
}
public void closeConnection(String connectionId){
/* Close connection and remove from map */
Connection connection = connections.get(connectionId);
if ( connection != null) {
connection.close();
connections.remove(connectionId);
}
}
public void broadcastMessage(String message){
for (Map.Entry<String, Connection> entry : connections.entrySet()){
entry.getValue().sendMessage(message);
}
}
}
サンプルサーバークラス:
class Server implements Runnable{
ServerSocket socket;
int id;
public Server(){
new Thread(this).start();
}
public void run(){
try{
ServerSocket socket = new ServerSocket(4567);
while(true){
Socket clientSocket = socket.accept();
++id;
Connection connection = new Connection(""+ id,clientSocket);
LazyConnectionManager.getInstance().registerConnection(connection);
LazyConnectionManager.getInstance().broadcastMessage("Message pushed by server:");
}
}catch(Exception err){
err.printStackTrace();
}
}
}
シングルトンのその他の実用例:
-
ThreadPool, ObjectPool, DatabaseConnectionPool
などのグローバルリソースの管理 -
DEBUG,INFO,WARN,ERROR
などの異なるログレベルのアプリケーションデータをLogging
するような集中サービス - グローバル
RegistryService
。起動時に異なるサービスが中央コンポーネントに登録されます。このグローバルサービスは、アプリケーションのFacade
として機能します
C#の例:マルチスレッドシングルトン
静的初期化はほとんどの状況に適しています。アプリケーションでインスタンス化を遅延させたり、デフォルト以外のコンストラクタを使用したり、インスタンス化の前に他のタスクを実行したり、マルチスレッド環境で作業する必要がある場合は、別の解決策が必要です。ただし、静的初期化の例のように、スレッドの安全性を保証するために共通言語ランタイムに依存することはできません。このような場合、特定の言語機能を使用して、複数のスレッドが存在する場合にオブジェクトのインスタンスが1つだけ作成されるようにする必要があります。より一般的な解決策の1つは、Double-Check Locking [Lea99]イディオムを使用して、別々のスレッドが同時にシングルトンの新しいインスタンスを作成しないようにすることです。
次の実装では、Singletonのインスタンスがまだ作成されていない場合、ロックブロックが識別するクリティカルエリアに1つのスレッドのみを入力できます。
using System;
public sealed class Singleton {
private static volatile Singleton instance;
private static object syncRoot = new Object();
private Singleton() {}
public static Singleton Instance {
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}
}
この方法では、インスタンスが1つだけ作成され、インスタンスが必要な場合にのみ作成されます。また、変数はvolatileであると宣言され、インスタンス変数にアクセスする前にインスタンス変数への代入が完了するようにします。最後に、このアプローチは、デッドロックを回避するために、型自体をロックするのではなく、ロックするためにsyncRootインスタンスを使用します。
このダブルチェックロックのアプローチは、スレッドの並行性の問題を解決し、Instanceプロパティメソッドへのすべての呼び出しで排他ロックを回避します。また、オブジェクトに初めてアクセスするまでインスタンス化を遅延させることもできます。実際には、アプリケーションはこのタイプの実装をめったに必要としません。ほとんどの場合、静的初期化の方法で十分です。
リファレンス:MSDN
謝辞
[ガンマ95]ガンマ、ヘルム、ジョンソン、ヴリシデス。デザインパターン:再利用可能なオブジェクト指向ソフトウェアの要素。 Addison-Wesley、1995。
[Lea99] Lea、Doug。 Javaでの並行プログラミング、第2版。 Addison-Wesley、1999。
[Sells03] Sells、Chris。 "封印されたサック。" sellsbrothers.comニュース。 http://www.sellsbrothers.com/news/showTopic.aspx?ixTopic=411から入手できます 。
シングルトン(PHP)
<?php class Singleton { /** * @var Singleton The reference to *Singleton* instance of this class */ private static $instance; /** * Returns the *Singleton* instance of this class. * * @return Singleton The *Singleton* instance. */ public static function getInstance() { if (null === static::$instance) { static::$instance = new static(); } return static::$instance; } /** * Protected constructor to prevent creating a new instance of the * *Singleton* via the `new` operator from outside of this class. */ protected function __construct() { } /** * Private clone method to prevent cloning of the instance of the * *Singleton* instance. * * @return void */ private function __clone() { } /** * Private unserialize method to prevent unserializing of the *Singleton* * instance. * * @return void */ private function __wakeup() { } } class SingletonChild extends Singleton { } $obj = Singleton::getInstance(); var_dump($obj === Singleton::getInstance()); // bool(true) $anotherObj = SingletonChild::getInstance(); var_dump($anotherObj === Singleton::getInstance()); // bool(false) var_dump($anotherObj === SingletonChild::getInstance()); // bool(true)
シングルトンデザインパターン(一般的に)
注:シングルトンはデザインパターンです。
しかし、それはまた、反パターンを考慮した。
シングルトンの使用は、使用する前に慎重に検討する必要があります。通常、より良い選択肢があります。
シングルトンの主な問題は、グローバル変数の問題と同じです。それらは外部グローバル可変状態を導入する。つまり、シングルトンを使用する関数は、入力パラメータに依存するだけでなく、シングルトンの状態にも依存します。これは、テストが深刻に危険にさらされる(難しい)ことを意味します。
シングルトンの問題は、作成パターンと組み合わせて使用することで軽減できます。シングルトンの初期生成を制御することができる。