列挙型とファクトリ戦略の組み合わせを使用して、文字列からオブジェクト インスタンスを作成し、文字列のセット (または配列) を提供する、単純でタイプ セーフな方法を使用できます。
次の例を見てください -
import java.util.HashMap;
import java.util.Map;
public enum FishType {
BLUE_FISH(BlueFish.class, new FactoryStrategy<BlueFish>(){
public BlueFish createFish(int x, int y) {
return new BlueFish(x, y);
}}),
RED_FISH(RedFish.class, new FactoryStrategy<RedFish>(){
public RedFish createFish(int x, int y) {
//an example of the increased flexibility of the factory pattern - different types can have different constructors, etc.
RedFish fish = new RedFish();
fish.setX(x);
fish.setY(y);
fish.init();
return fish;
}});
private static final Map<Class<? extends Fish>, FactoryStrategy> FACTORY_STRATEGY_MAP = new HashMap<Class<? extends Fish>, FactoryStrategy>();
private static final String[] NAMES;
private FactoryStrategy factoryStrategy;
private Class<? extends Fish> fishClass;
static {
FishType[] types = FishType.values();
int numberOfTypes = types.length;
NAMES = new String[numberOfTypes];
for (int i = 0; i < numberOfTypes; i++) {
FishType type = types[i];
FACTORY_STRATEGY_MAP.put(type.fishClass, type.factoryStrategy);
NAMES[i] = type.name();
}
}
<F extends Fish> FishType(Class<F> fishClass, FactoryStrategy<F> factoryStrategy) {
this.fishClass = fishClass;
this.factoryStrategy = factoryStrategy;
}
public Fish create(int x, int y) {
return factoryStrategy.createFish(x, y);
}
public Class<? extends Fish> getFishClass() {
return fishClass;
}
public interface FactoryStrategy<F extends Fish> {
F createFish(int x, int y);
}
@SuppressWarnings("unchecked")
public static <F extends Fish> FactoryStrategy<F> getFactory(Class<F> fishClass) {
return FACTORY_STRATEGY_MAP.get(fishClass);
}
public static String[] names() {
return NAMES;
}
}
この列挙型は、次の方法で使用できます -
Fish fish = FishType.valueOf("BLUE_FISH").create(0, 0);
また
Fish fish = FishType.RED_FISH.create(0, 0);
または、作成された魚の種類を知る必要がある場合は、この呼び出しを使用できます -
BlueFish fish = FishType.getFactory(BlueFish.class).createFish(0, 0);
メニューにアイテムを追加したり、その他の理由ですべての魚の種類を取得したりするには、names() メソッドを使用できます -
String[] names = FishType.names();
新しい型を追加するために編集する必要がある唯一のコードは、次のような新しい enum 宣言を追加することです。
GREEN_FISH(GreenFish.class, new FactoryStrategy<GreenFish>(){
public GreenFish createFish(int x, int y) {
return new GreenFish(x, y);
}}),
たくさんのコードのように見えるかもしれませんが、すでに書かれており、他のコードから呼び出すためのクリーンな API を提供し、かなり優れた型安全性を提供し、魚の実装が必要なコンストラクターまたはビルダーを柔軟に持つことができます。高速に実行する必要があり、任意の文字列値を渡す必要はありません。
本当に簡潔にしたい場合は、列挙型でテンプレートメソッドを使用することもできます-
public enum FishType {
BLUE_FISH(){
public BlueFish create(int x, int y) {
return new BlueFish(x, y);
}
},
RED_FISH(){
public RedFish create(int x, int y) {
return new RedFish();
}
};
public abstract <F extends Fish> F create(int x, int y);
}
これにより、次のような多くの同じ機能を引き続き利用できます。
Fish fish = FishType.valueOf("BLUE_FISH").create(0, 0);
と
Fish fish = FishType.RED_FISH.create(0, 0);
そしてさえ
RedFish fish = FishType.RED_FISH.create(0, 0);