String data
をいくつかのデータとともに取得し、それを特定の種類のオブジェクトに解析するシナリオを考えてみましょうAnimal
。免責事項:長いですが、これは sscce です。私の実際のプロジェクトは、猫の音とはほとんど関係がありません:)
要件:
- 最初の文字は「動物の種類」を示します。だから
C
を参照するかもしれませんしabstract class Cat
、 を参照するD
かもしれませんabstract class Dog
。 - 2 番目の文字は、オプションで「動物のサブタイプ」を示します... ただし、これらのサブタイプはカテゴリにグループ化されます (クラスに関する限り)。したがって、 aは引数付きである
CS
可能性がありThaiCat extends Cat
、引数付き"Siamese"
であるCK
可能性があり、ThaiCat extends Cat
引数付き"Korat"
でCB
ある可能性がAmericaCat extends Cat
ありますBengal
- に
data
String
は他の情報があります。たとえば、動物の名前が含まれている場合があります。このデータを解析する方法について心配する必要はありません。このコードは 間で共有されますabstract class
(すべてのサブタイプに当てはまるものを解析できCat
、サブクラスは残りの必要なデータを解析します)。
最初の解決策は、これから始めます:
public enum AnimalType {
CAT ('C') { Animal makeAnimal(String data) { return CatType.makeCat(data); },
DOG ('D') { Animal makeAnimal(String data) { return DogType.makeDog(data); };
private char type;
public char getType() { return type; }
private AnimalType(char type) { this.type = type; }
abstract Animal makeAnimal(String data);
private static Map<Character, AnimalType> animalMap = new HashMap<>();
static {
for(AnimalType currentType : AnimalType.values()) {
animalMap.put(currentType.getType(), currentType());
}
}
public static Animal makeAnimal(String data) {
return animalMap.get(data.charAt(0)).makeAnimal(data);
}
}
public enum CatType {
BENGAL ('B') { Cat makeCat(String data) { return new AmericaCat(data, this) },
RAGDOLL ('R') { Cat makeCat(String data) { return new AmericaCat(data, this) },
KORAT ('K') { Cat makeCat(String data) { return new ThaiCat(data, this) },
SIAMESE ('S') { Cat makeCat(String data) { return new ThaiCat(data, this) };
private char type;
public char getType() { return type; }
private CatType(char type) { this.type = type; }
abstract Cat makeCat(String data, CatType type);
private static Map<Character, CatType> catMap = new HashMap<>();
static {
for(CatType currentType : CatType.values()) {
catMap.put(currentType.getType(), currentType());
}
}
static Cat makeCat(String data) {
return catMap.get(data.charAt(1)).makeCat(data);
}
}
これはすべてうまくいっています。高速でクリーンで、適切なコード委任などである必要があります。ただし。では、突然動物に依存関係が生じたらどうなるでしょうか (私は Guice を使用しています)。動物の鳴き声を含むライブラリがあり、できるようにしたいとします。animal.speak()
サウンド オブジェクトを呼び出す機能は、Animal
.
ここに私が考えたいくつかのことがあります:
- ->サブクラスのペアリング
MapBinder
をセットアップするために使用します。次に、マップをファクトリ クラスにバインドし、作成後にメソッド呼び出しとしてオブジェクトに渡します。Enum
Cat
Map<K, Provider<V>>
data
Cat
- AssistedInject ファクトリを作成し、各列挙の
makeCat
メソッドがファクトリ内の正しいメソッドを呼び出すようにします。問題は、Enumeration インスタンスにファクトリを注入できないことです。Guice は静的注入を使用しないことを推奨しています。したがって、メソッド チェーンのずっと下まで自分のファクトリを渡す必要がありますが、これは目的に反しているように見えます。また、これは、間違ったコンストラクターが間違った文字列によって呼び出されることを許可しないという問題を解決しません。 - 手動ファクトリ オブジェクトを作成します。ただし、ファクトリがどの程度の作業を行う必要があり、列挙型 (存在する場合) がどの程度の作業を行うべきかはわかりません。
最善の解決策は何ですか?