web-dev-qa-db-ja.com

モノステートvs.シングルトン

グローバルオブジェクトを維持するためにシングルトンの代わりにモノステートパターンを使用するシナリオは何ですか?

編集:私はシングルトンとモノステートのパターンが何であるかを知っています。また、かなりの数のシナリオでシングルトンを実装しました。 MonoStateパターンを実装する必要があるシナリオ(事例)を知りたいだけです。

例えば。 Windowsフォームアプリで画面ごとの列のリストを維持する必要があります。この場合、シングルトン辞書を使用できます。ただし、静的グローバル変数にリストを格納しており、ScreenDetails.ScreenNameをキーとして指定してScreenDetailsを取得できるインデクサーを提供したいと思いました(キーが存在しない場合はリストに新しいエントリを動的に追加する必要があるため) .ColumnsTable。インデクサーは静的クラスを操作できないため、パターンをモノステートに変更しました。

したがって、他のどのシナリオがユーザーにシングルトンの代わりにモノステートを使用せざるを得ないのか知りたいのです。

45
Rashmi Pandit

そのベースでは、モノステートはシングルトンの周りの単なる構文糖衣です。モノステートが興味深いのは、サブクラス化を開始するときです。サブクラスは、共有状態をさまざまな動作で装飾できるためです。

単純な-多少工夫が凝らされていてあまり効率的でない場合:)-例:

public class GlobalTable implements Iterable<Key> {

  /** Shared state -- private */    
  private static final Map<Key, Value> MAP = new LinkedHashMap<Key, Value>();

  /** Public final accessor */    
  public final Value get(Key key) {
    return MAP.get(key);
  }

  /** Public final accessor */    
  public final boolean put(Key key, Value value) {
    return MAP.put(key);
  }

  /** Protected final accessor -- subclasses can use this to access
      the internal shared state */    
  protected final Set<Key> keySet() {
    return MAP.keySet();
  }

  /** Virtual -- subclasses can override for different behavior */    
  public Iterator<Key> iterator() {
    return Collections.unmodifiableSet(MAP.keySet()).iterator();
  }
}

インデックス付きアクセスが必要な場合はどうなりますか?

public class IndexedGlobalTable extends GlobalTable {

  public List<Key> getKeysAsList() {
    return Collections.unmodifiableList(new ArrayList<Key>(keySet()));
  }

  public Key getKeyAt(int index) {
    return getKeysAsList().get(index);
  }

  public Value getValueAt(int index) {
    return get(getKeyAt(index));
  }
}

ソートされたキーはどうですか?

public class SortedGlobalTable extends GlobalTable {

  @Override
  public Iterator <Key> iterator() {
    return Collections
      .unmodifiableSortedSet(new TreeSet<Key>(keySet())).iterator();
  }

}

データのいずれかのビューが必要なときはいつでも、適切なサブクラスをインスタンス化するだけです。

もちろん、そもそもグローバルデータが本当に良いアイデアであるかどうかは別の問題ですが、少なくともMonostateを使用すると、データの使用方法をより柔軟に設定できます。

17
David Moles

モノステートとシングルトンは、同じメダル(グローバルステート)の2つの面です。

  • モノステートは動作(すべてのクラスインスタンスに沿って1つの値のみ)を強制します
  • シングルトンは構造的制約(1つのインスタンスのみ)を強制します

シングルトンの使用法は透過的ではありません

つまり:

Singleton singleton = Singleton.getInstance();

モノステートの使用は透過的です

つまり:

MonoState m1 = new MonoState();
MonoState m2 = new MonoState(); // same state of m1 
67
dfa

これがロバートC.マーチンがそれについて言わなければならないことです: シングルトン対モノステート(pdf)

SINGLETONは、派生によって制約する既存のクラスがあり、アクセスを取得するために全員がinstance()メソッドを呼び出す必要があることを気にしない場合に最適です。モノステートは、クラスの特異な性質をユーザーに対して透過的にしたい場合、または単一オブジェクトの多形導関数を使用したい場合に最適です。

41
egaga

シングルトンとモノステートは非常に危険なパターンであることに注意してください。それらは、シングルトンにしたいオブジェクトの存続期間について考える必要がない怠惰なコーダーによって誤用される傾向があります。それらはテストをより困難にし、緊密に結びついた柔軟性のないシステムを作成します。

シングルトンまたはモノステートが本当に必要な状況を見つけることは非常にまれです。オブジェクトコラボレーションの推奨される方法は、依存性注入です。

これについてはたくさん書かれています:

8
Ed Sykes

2つのパターンの違いは、動作と構造の1つです。 [〜#〜] singleton [〜#〜]パターンは、特異点の構造を強制します。これにより、複数のインスタンスが作成されるのを防ぎます。一方、[〜#〜] monostate [〜#〜]は、構造上の制約を課すことなく、特異点の動作を強制します。

SINGLETONのメリット

  • すべてのクラスに適用できます。コンストラクターをプライベートにし、適切な静的関数と変数を追加するだけで、任意のクラスをSINGLETONに変更できます。
  • 派生によって作成することができます。クラスを指定すると、SINGLETONであるサブクラスを作成できます。
  • 遅延評価。 SINGLETONが使用されない場合、作成されることはありません。

シングルトンのコスト

  • 破壊は未定義です。 SINGLETONを破壊または廃止する良い方法はありません。インスタンスを無効にする廃止方法を追加した場合でも、システム内の他のモジュールがSINGLETONインスタンスへの参照を保持している可能性があります。その後インスタンスを呼び出すと、別のインスタンスが作成され、2つの同時インスタンスが存在します。

  • 継承されません。 SINGLETONから派生したクラスはシングルトンではありません。 SINGLETONにする必要がある場合は、静的関数と変数を追加する必要があります。

  • 効率。インスタンスを呼び出すたびに、ifステートメントが呼び出されます。これらの呼び出しのほとんどでは、ifステートメントは役に立ちません。

  • 不透明。 SINGLETONのユーザーは、Instanceメソッドを呼び出す必要があるため、SINGLETONを使用していることを知っています。

MONOSTATEのメリット

  • 透明性。 MONOSTATEのユーザーは、通常のオブジェクトのユーザーと同じように動作します。ユーザーは、オブジェクトがMONOSTATEであることを知る必要はありません。

  • 派生性。 MONOSTATEの導関数はMONOSTATESです。実際、MONOSTATEのすべての派生物は、同じMONOSTATEの一部です。それらはすべて同じ静的変数を共有します。

  • ポリモーフィズム。 MONOSTATEのメソッドは静的ではないため、導関数でオーバーライドできます。したがって、異なるデリバティブは、静的変数の同じセットに対して異なる動作を提供できます。

  • 明確に定義された作成と破壊。 MONOSTATEの変数は静的であるため、作成時間と破棄時間が明確に定義されています。

MONOSTATEのコスト

  • 変換なし。通常のクラスは、派生によってMONOSTATEクラスに変換することはできません。

  • 効率。 MONOSTATEは実際のオブジェクトであるため、多くの作成や破壊を経る可能性があります。これらの操作は多くの場合コストがかかります。

  • プレゼンス。 MONOSTATEが使用されない場合でも、MONOSTATEの変数はスペースを占有します。

アジャイルソフトウェアの開発、原則、パターン、および実践Robert C. Martin

1
Mohammad Akbari