13

これは、シングルトンの何が悪いのかについてのいくつかのコメントへの回答です。

そこでは、シングルトンの代わりにプロキシ パターンを使用して DB データをキャッシュできることが提案されました。しかし、私には利点がわかりません。実際、シングルトンはより「制御可能」に見えます。

問題について詳しく説明しましょう。大規模なデータ セットを含むデータベースがあり、変更されないため読み取り専用と見なすことができると仮定すると、このデータ キャッシュをモデル化する方法として、シングルトンよりもプロキシ パターンの方が適しているのはなぜでしょうか?

(追伸: 「より「テスト可能」だから!」と言う場合は、詳しく説明してください。私はまだこれらの概念に慣れています)

ご協力いただきありがとうございます!

4

3 に答える 3

9

免責事項:ここではJava用語で話しています

シングルトンは、アプリケーション全体でデータを共有するための迅速かつ便利な方法であるため、最近頻繁に悪用されているため、アンチパターンと見なされるようになりました。これは、共有リソースへのアクセス制御を提供するのにより適した設計パターンの拡張です。 .

プログラムの標準出力を検討してください。そのリソースへのアクセスは、書き込みの同期を可能にするために単一のアクセスポイントによって保護される必要があります。そのため、たとえば System.out を java.

問題は、シングルトンを使い始めると、自分がやっていることのすべての核心的な詳細を知る必要があるということです.シングルトンクラスについて多くの厳密な仮定をしているため、最も重要なのはそれが唯一のものになるということです.システム内のクラス。次に、それが常にリソースへの単一のエントリ ポイントであると想定して使用を開始すると、厄介なバグが発生します。これは、クラスが ejb サーバーにデプロイされ、各 ejb コンテキストに独自のシングルトンがあり、さらにもう 1 つのシングルトンがあるためです。サーバーからリロードされたすべての jsp に加えて、シングルトンがシリアライズおよびデシリアライズされるたびに 1 つのシングルトン (おそらく readResolve() メソッドをオーバーライドするのを忘れているため)。

そのため、シングルトンは細心の注意を払って使用する必要があり、意図した用途には完全に役立つにもかかわらず、現在ではアンチパターンと見なされています。

データベース キャッシュの場合は、この「キャッシュ」リソースのプロキシを使用してキャッシュを必要とする各クラスを用意する方がよいため、代わりにプロキシ自体に「リソースを検索する」ロジックを追加できます。ロジックをキャッシュシングルトンの取得に関連付けることができます。これは、環境によって機能する場合と機能しない場合があります。

したがって、リソースへの共有アクセスを行う手段としてシングルトンを使用することは悪いことです。リソースを見つける方法をハードコーディングしている(そしてシングルトンの落とし穴を無視している)ため、同期目的でリソースを制御するシングルトンを使用することは完全に受け入れられます。

セマフォについて考えてみてください。これらは、常に同じセマフォを取得できる場合にのみ機能します。この後者の場合、問題になる可能性があるのは、そのセマフォにアクセスする必要があるすべての場所からシングルトンにアクセスすることです。ここでは、シングルトンをラップして、セマフォ自体のライフサイクルをより細かく制御するクラスが必要になります。

プロキシは、単一のアプリケーション、クライアントサーバーシステム、同じシステムのさまざまなコンポーネントなど、「システム全体にリソースを提供する」という役割をカバーすることを目的としています。リソースは不透明です。キャッシュされた値のハッシュマップを含むシングルトンを提供する、ネットワーク上のどこかで memcached にアクセスする、テスト中に csv を読み取る、アプリケーションからそれらを呼び出す方法をすべて変更することなく提供することができます。

于 2010-02-01T22:31:30.760 に答える
2

私の意見では、「どちらか、または」はありません。クラスは、同時に複数の設計パターンを実装できます。外部データベースへのアクセスを実装するクラスは、いずれにしてもプロキシ (この場合はリモート プロキシ) であると言えます。キャッシングを追加機能と考える場合、それはデコレーターでもあります。

それで、本当の問題は、それもシングルトンであるべきかということです? 外部データベースが 1 つだけあるとします。CachingDBProxy は 1 つだけ必要ですか? 私は言うでしょう、それは用途に依存します:

同様のデータにアクセスするクライアントが複数ある場合、同じ CachingDBProxy を共有すると明らかにメリットがあります。あるクライアントが必要とするデータは、別のクライアントがすでに必要としている可能性があるため、データベースへのコストのかかるアクセスを実行する代わりに、キャッシュからデータを取得できます。

一方、一部のクライアントは、まったく異なるデータにアクセスする場合があります。そのため、CachingDBProxy が 1 つのクライアント グループによる限られた量のデータ アクセスのみをキャッシュすると仮定すると、別のクライアント グループが必要としているデータが破棄され、キャッシュ パフォーマンスが低下する可能性があります。この場合、データベースが 1 つしかなくても、複数の CachingDBProxy を用意するのが合理的かもしれません (もちろん、これは同時アクセスが可能であることを前提としています)。

そのため、CachingDBProxy の数は用途によって異なります。CachingDBProxy は、正当な理由なしにその使用を制限するべきではありません。そのため、インスタンスが 1 つしかないことを強制するべきではありません。したがって、この場合、CachingDBProxy はシングルトンであってはなりません。クライアントだけが、どれだけの CachingDBProxy が適切かを知ることができます。

一方、一度に 1 つのアクセスしか処理できない特定のリソースのプロキシがある場合、それはシングルトンでなければならない場合があります。しかし、それは上記のケースとは別のケースです。ここで、要件は、プロキシが担当する領域から直接取得されます (その目的は、その特定のリソースへのアクセスをチャネリングすることです)。

于 2010-01-30T15:47:36.080 に答える
0

キャッシュされたデータとデータのロード (別名遅延ロード) の間のプロキシにプロキシ パターンが使用されているとしか想像できません。

並べ替え:

class DbProxy
{
  private static Data cache = null; // Sort-of Singleton

  public static Data GetData(String query)
  {
    if (DbProxy.cache == null)
    {
      // Data = Do Stuff to read Data
      DbProxy.cache = Data;
    }
    return DbProxy.cache;
  }
}

これには、これを使用するコードがデータが既に存在するかどうかを気にする必要がなく、GetData を呼び出して実行するだけでよいという利点があります。

/* 免責事項: コードは有効ではありません。デモンストレーション用の疑似コードです */

于 2010-01-19T15:17:11.003 に答える