11

それぞれが一意の識別子を持つ一連のオブジェクトを作成することを目指しています。その識別子を持つオブジェクトが既に存在する場合は、既存のオブジェクトを使用したいと考えています。それ以外の場合は、新しいものを作成したいと思います。ここでは汚い言葉だとわかっているので、シングルトンという言葉を使用しないようにしています...

ファクトリメソッドを使用できます:

    // A map of existing nodes, for getInstance.
private static Map<String, MyClass> directory = new HashMap<String, MyClass>();

public static MyClass getInstance(String name) {
    MyClass node = directory.get(name);
    if(node == null) {
       node == new MyClass(name);
    }
    return node;
}

または、別の MyClassFactory メソッドを持つこともできます。

しかし、私は MyClass をサブクラス化するつもりでした:

public class MySubClass extends MyClass;

これ以上何もせず、MySubClass.getInstance() を呼び出すと:

MyClass subclassObj = MySubClass.getInstance("new name");

... その場合、subclassObj は MySubClass ではなく、プレーンな MyClass になります。

それでも、すべてのサブクラスで getInstance() をオーバーライドするのはハックに思えます。

私が見逃しているきちんとした解決策はありますか?


それが質問の一般化されたバージョンです。回答者がそれらを求めたので、より具体的に。

このプログラムは、ソフトウェアを表すノード間の依存関係の有向グラフを生成するためのものです。サブクラスには、Java プログラム、Web サービス、ストアド SQL プロシージャ、メッセージ駆動型トリガーなどが含まれます。

したがって、各クラスはこのネットワークの「要素」であり、他のノードとの依存関係をナビゲートおよび変更するためのメソッドがあります。サブクラス間の違いはpopulate()、適切なソースからオブジェクトをセットアップするために使用されるメソッドの実装です。

「login.java」という名前のノードが、「checkpasswd.sqlpl」に依存していることを学習したとします。

this.addDependency( NodeFactory.getInstance("checkpasswd.sqlpl"));

問題は、この時点で checkpasswd.sqlpl オブジェクトが存在する場合と存在しない場合があることです。

4

7 に答える 7

5

Guiceを調べましたか?問題を正確に解決できるかどうかはわかりませんが、ジェネリック ファクトリおよび依存性注入コンテナーとして機能し、タイプ セーフでない文字列キーを排除します。

于 2008-11-25T16:35:23.290 に答える
4

静的メソッドは親クラスで定義され、静的にも呼び出されます。したがって、サブクラスでメソッドを呼び出したことをメソッドで知る方法はありません。Java コンパイラは、呼び出しを親クラスへの呼び出しに静的に解決することさえあります。

したがって、提案どおりに子クラスで静的メソッドを再実装するか、継承できるようにそれらを非静的にする必要があります (クラスではなく、ファクトリオブジェクトの階層で)。または、必要な型を示すパラメーターを渡す必要があります。作成。

EnumSet.noneOf() メソッドを確認してください。あなたと同様の問題があり、 java.lang.Class メソッドを渡すことで解決します。クラスで newInstance を使用できます。しかし、個人的には、静的メソッドを持つクラスではなく、ファクトリ オブジェクトを使用します。

于 2008-11-25T16:12:59.043 に答える
2

問題の説明を読んだ後、グラフ構築でサブクラス化することで、自分にとって非常に困難になっていると思います。依存グラフを「プログラム情報」から切り離すと、問題ははるかに単純になると思います

次のようなインターフェイスを使用します。

Public Interface Node<T> {
  public Object<T>    getObject();
  public String       getKey();
  public List<String> getDependencies();
  public void         addDependence(String dep);
}

次に、ファクトリを使用してノードをインスタンス化します

于 2008-11-27T09:48:16.527 に答える
1

Class クラスは、作成できるインスタンスのタイプでパラメータ化されます。(例: Class<String> は String インスタンスのファクトリです。)

ここでファクトリ メソッドを使用して getOrCreate するときに作成する必要があるインスタンスの型を知る方法が見当たらないので、それをメソッドに渡し、生成される型をパラメータ化することをお勧めします。

private static Map<String, MyClass> directory = new HashMap<String, MyClass>();

public static <T extends MyClass> T getInstance(String name, Class<T> generatorClass)
{
  MyClass node = directory.get(name);    
  if(node == null) {
    node = generatorClass.getConstructor(String.class).newInstance(name);
    directory.put(name, node);
  }
  return node;
}

また、実際には新しく構築されたノードをディレクトリに配置していないことに気付きました-それは見落としだと思います。このメソッドを、ジェネレーターを使用せず、デフォルトの型にハードコーディングされていない別のメソッドでオーバーロードすることもできます。

public static MyClass getInstance(String name) {
  return getInstance(name, MyClass.class);
}
于 2008-11-25T16:36:01.133 に答える
1

クラスが存在しない場合、それがどのクラスであるべきかをどこかで知っていることを暗示しているようです。そのロジックをファクトリに実装すると、正しいクラスが得られるはずです。

このようにして、ファクトリから実際に返されたクラスを知る必要もありません。

Factoryパターンを検討している場合は、「MyClass」もインターフェイスにする可能性があります。

于 2008-11-25T16:44:58.463 に答える
0

おそらく依存性注入が必要です。それはあなたがやろうとしていることをいくらか一般化するでしょう。

また、継承はおそらくあなたが必要としているものとは正確には一致しません。「is-a」テストに合格できない限り、絶対に使用しないでください。継承されたクラスが「Has-a」の一意の文字列タグ(基本的にはクラスのように見える)である場合、それは「is-a」を意味するわけではありません...

ただし、一方を他方に保持させることもできます。おそらくかなりの数の解決策がありますが、A)要件のリスト全体を投稿しなかったため、推測するしかありません。B)おそらく必要なのは依存性注入です。:)

于 2008-11-25T18:09:27.577 に答える
0

パターンは一種のFlyweightのように見えます(意図と完全に一致しない場合、構造的に)。

説明されているように、populateメソッドはパターンにマッピングできますが、Template必ずしも表現された問題に対処しているわけではありません。

私が提案したいのは、あなたが期待するさまざまなタイプのcreate(シングルトンを意味する の代わりに)メソッドを使用したファクトリの一般化です。getInstance

public static MyClass createJavaNode(String name, <differentiator>);
public static MyClass createSqlPlNode (String name, <differentiator>);
.
.
.

namea が a にどのようにマップされるかについての知識<differentiator>は、実際には実装上の選択です。理想的には、ポリモーフィックが存在し、型createによる差別化が行われnodeます。createメソッドは を返しますが、MyClass実際にはサブクラスを返しています。MyClassメソッドを使用して、インターフェースまたは抽象クラスのいずれかを作成することを強く検討しますabstract populate( がありますTemplate)。

説明から、タイプ間で異なるのはサブクラス自体の動作ではなく、作成動作であるように見えるためMyClass、インターフェイスまたは抽象クラスへのリファクタリングのケースが強​​くなります。

RA Heinlein の言葉を言い換えると、TANSTAAFL「Free lunch などというものはありません」という言葉がありますが、さまざまなタイプを作成する方法に関する知識がアプリケーションのどこかに存在している必要があります。したがって、他のいくつかの回答が表明しているように、その知識を Factory クラスに入れるか、どの実装をどのように作成するかの決定を分離するかを選択します。ファイルシステムをスキャンしてそこNodeから s を収集する機能があるようです。そのコードは、作成されるべき( whatへの答え) のを知る (または知ることができる) でしょう。Node

それがオブジェクト指向の方法として実装されるswitchか、よりオブジェクト指向の方法で実装されるか (テーブル駆動のディスパッチが適している場合の 1 つ) は、あなた次第です。これが役立つ可能性がある場合は、ここでそれを拡張できます。

ところで、MyClass一部のサブクラスで のコア動作を拡張または変更する必要がある場合は、 aDecoratorが役立つ可能性があります。


元の回答:

デコレータまたはテンプレート デザイン パターンを代替案として検討することもできます。

于 2008-11-25T16:17:36.257 に答える