私はプロジェクトに取り組み、有効な解決策を見つけましたが、コードのいくつかの問題をどのように解決したかについていくつか質問を受けました。まず第一に、私はデザインパターンの専門家ではありませんが、シングルトンの(アンチ)パターンを知っているので、通常は回避します。しかし、私がよく使用するのは、static
ヘルパー/ユーティリティメソッドです。
したがって、私が取り組んできたプロジェクトは、Atlassian Plugin SDKに基づいています。私はサーブレットを実装し、Atlassianコンポーネントを介していくつかのデータにアクセスしました。ページのレンダリングに関しては、AtlassianプラットフォームはApache Velocityを使用します。だから私は私のコンテキストマップを構築し、Velocityのオブジェクトにアクセスし、すべてがうまくいきます。ある時点で、他のサーブレットまたはページにリンクするURLを生成したいと考えています。そこで、static
url生成メソッドを使用してクラスを作成します。残念なことに、Velocityコンテキスト(スコープを定義する)に渡すことができるインスタンスがないため、Velocityでこれらのメソッドにアクセスできません。 But Velocityでは、クラスのインスタンスを介して静的メソッドを使用できます。結果のクラスは次のようになります(Javaコード)。
public class Urls {
private static Urls Singleton = new Urls();
public static Urls getInstance() {
return Singleton;
}
private Urls() { }
public static String getBaseUrl() { ... }
public static String forUserProfile(ApplicationUser user) { ... }
...
}
これで、通常のJava=コードでは、静的メソッドを簡単に使用できます。
String myUrl = Urls.forUserProfile(myUser);
しかし、シングルトンをベロシティコンテキストに渡すこともできます...
context.put("urls", Urls.getInstance());
...私のVelocityテンプレートで使用するには:
<a href="$urls.forUserProfile($myUser)">User profile</a>
この「パターン」または類似のパターンをプロジェクトで何度か使用しました。このような名前はありますか?通常は静的メソッドに簡単にアクセスできるため、これは少しまれだと思います。私が忘れていた大きな欠点はあると思いますか?この方法を使用しない理由はありますか?より良い方法はありますか?
Urls
は状態がないため、シングルトンとしては有用ではありません。通常のコードでインスタンス化しないこともできます。
public class Urls {
public Urls() { }
// static methods ...
}
context.put("urls", new Urls());
状態のないシングルトンは意味がないため、1つのインスタンスのみを強制する必要はありません。そして、インスタンスが必要な場合は、インスタンスを使用します。
しかし、継ぎ目なくステートレスなシングルトンの状態が存在する可能性があります。複数の実装が可能で、状態は使用している実装です。そして、システム全体が同じ実装を使用するという要件は理にかなっているので、それをある種の注入可能なシングルトンにします(Java外部フレームフレームなしでは、ServiceLoaderを使用して、実行時に利用可能な実装に基づいてインスタンスを作成できます)。
シングルトンパターンの最も不幸な側面の1つは、GoFパターンの本で説明されているものよりもはるかに単純であることが広く理解されていることです。非常に微妙ですが、そのパターンのコード例を見ると、複数の具象実装を持つ抽象シングルトンクラスが表示されます。ほとんどの人はシングルトンを単にグローバルオブジェクトと考えていますが、それは実際には正しくありません。
それを無視すると、状態なしのシングルトンが存在しても意味がありません。ただし、ポリモーフィズムを考慮すれば可能です。たとえば、丸めなどの特定の会計計算の実装方法に関するグローバルルールを構成できる必要があるアプリケーションがあるとします。だからあなたはそのようなクラスを持っています:
public abstract class Accounting
{
public static final Accounting getInstance()
{
//...
}
public abstract Money round(Money money);
}
次に、このAccountingクラスの異なるバージョンを作成し、アプリケーションの特定のインスタンスで使用されるバージョンを構成するなんらかの方法を実装します。これらのオブジェクトが有用であるために状態を含むことは本当に重要ではありません。それらを使用してメソッド実装を交換する機能で十分です。
DIは、この種のことについてはより流行しているし、それははるかに多くの柔軟性を提供します。その柔軟性が必要ない場合、または実際にリスクが生じる場合は、ポリモーフィックシングルトンアプローチを検討する価値があります。このアプローチでは、DIを使用してシングルトンインスタンスを構成することを妨げるものは何もありません。
過去の経験に基づいて、私がシングルトンパターンを説明していないと主張し、いくつかのWebページを証明として指摘する可能性があります。 GoFの本の例を含め、実際にパターンを読むようにその意見を持つ人にお願いします。このパターンを説明するほとんどのWebサイトは、グローバルオブジェクトの実装方法を実際に説明しているだけです。
状態のないシングルトンのようなものはありません。単一インスタンスへのポインタは状態です。このポインターは、唯一のインスタンスを識別するだけでなく、インスタンスのタイプとその [〜#〜] vmt [〜#〜] および/またはディスパッチテーブルも定義します。つまり、動作を決定します。同じように。
メンバー変数のないオブジェクトを返すシングルトンについて質問していると思います。
...これは、唯一無二のものへの参照を含む静的変数です。その他の状態は、シングルトンパターンに固有のものではありません。
シングルトンはまた、貧乏人の factory でもあります。 Instance
への呼び出しは常に同じオブジェクトを返す必要があります(はい)が、シングルトンクラス自体から継承する任意のタイプのオブジェクトである可能性があります。したがって、ポリモーフィズムのためにシングルトンパターンを保持することができます。たとえば、DatabaseContext.Current
構成に応じてOracleContext
またはSqlServerContext
を返す可能性のあるシングルトンの一種。
シングルトンに現在メンバー変数がない場合でも、後で追加することができます。追加は簡単です。パターンを廃止すると、それらのメンバー変数が必要になったときに後で復元することが難しくなります。
YAGNIについて-シングルトンパターンが概念的に問題のドメインにマッピングされ、追加の作業がそれほど多くない限り、YAGNIにもかかわらず、正当な設計決定である可能性があります。
最近では誰もがシングルトンを嫌っています。より最近のアプローチは、プロセスごとのインスタンスで依存性注入を使用することです。 DIを使用すると、自動化された単体テストに必要な分離を簡単に作成できます。