シングルトンのように動作するが、そうではないコードを探しています(シングルトンが悪いため:)私が探しているものはこれらの目標を満たさなければなりません:
- スレッドセーフ
- シンプル(理解して使用する、つまり数行のコード。ライブラリ呼び出しは問題ありません)
- 速い
- シングルトンではありません。テストの場合、値を上書き(およびテスト後にリセット)できる必要があります。
- ローカル(必要な情報はすべて1か所にある必要があります)
- レイジー(値が実際に必要な場合にのみ実行)。
- 1回実行(RHSのコードは1回だけ実行する必要があります)
コード例:
private int i = runOnce(5); // Set i to 5
// Create the connection once and cache the result
private Connection db = runOnce(createDBConnection("DB_NAME"));
public void m() {
String greet = runOnce("World");
System.out.println("Hello, "+greet+"!");
}
フィールドは静的ではないことに注意してください。式のRHS(右側)だけが...ある程度「静的」です。i
テストでは、greet
一時的に新しい値を挿入できる必要があります。
また、このコードは、この新しいコードの使用方法の概要を示していることにも注意してください。runOnce()を何かに置き換えるか、別の場所(コンストラクター、多分、またはinit()メソッドまたはゲッター)に移動してください。ただし、LOCが少ないほど良いです。
いくつかの背景情報:
私はSpringを探していません。最も一般的なケースに使用できるコードを探しています。インターフェースを実装する必要があり、必要なテストを除いて2番目の実装はありません。モックオブジェクトを渡します。また、Springは#2、#3、#5に失敗します。構成言語を学ぶ必要があります。アプリコンテキストをどこかに設定する必要があります。XMLパーサーが必要であり、ローカルではありません(情報はいたるところに分散しています)。
#5のため、グローバル構成オブジェクトまたはファクトリは法案を満たしていません。
static final
#4のためにアウトです(ファイナルを変更できません)。static
クラスローダーの問題のためににおいがしますが、おそらく内部で必要になりますrunOnce()
。式のLHSでそれを避けられるようにしたいと思います。
考えられる解決策の1つは、同じオブジェクトを返すデフォルト設定でehcacheを使用することです。キャッシュに入れることができるので、いつでも値を上書きすることができます。しかし、おそらくehcacheよりもコンパクトでシンプルなソリューションがあります(これもXML構成ファイルなどが必要です)。
[編集]なぜそんなに多くの人がこれに反対するのか疑問に思います。これは有効な質問であり、ユースケースはかなり一般的です(少なくとも私のコードでは)。それで、あなたが質問(またはその背後にある理由)を理解していない場合、またはあなたが答えを持っていないか、あなたが気にしない場合、なぜ反対票を投じますか?:/
[EDIT2] Springのアプリコンテキストを見ると、すべてのBeanの99%以上に単一の実装しかないことがわかります。あなたはもっと持つことができますが、実際には、あなたは単にそうではありません。したがって、インターフェイス、実装、構成を分離する代わりに、実装(最も単純な場合)、current()メソッド、およびcurrent()の結果を初期化するための1行または2行の巧妙なコードのみを含むものを探しています。 1回(初めて呼び出されたとき)、同時に結果をオーバーライドできます(可能な場合はスレッドセーフ)。これをアトミックな「if(o == null)o = new O(); return o」と考えてください。ここで、oをオーバーライドできます。たぶん、AtomicRunOnceReferenceクラスが解決策です。
今のところ、私たち全員が毎日持っているものや使用しているものは最適ではなく、私たち全員が頭を叩いて「それだけ」と言うような不可解な解決策があると感じています。数年前に春が来たときに感じたように、私たちはすべてのシングルトンの問題がどこから来たのか、そしてそれらをどのように解決するのかを理解しました。