考虑一个场景,我想获取String data
一些数据并将其解析为某种对象,比如Animal
. 免责声明:尽管它很长,但这是一个 sscce;我的实际项目与猫的声音没什么关系:)
要求:
- 第一个字符表示“动物的类型”。所以
C
可以指abstract class Cat
,也D
可以指abstract class Dog
。 - 第二个字符可选地表示“动物的亚型”......除了这些亚型被分组(就类别而言)。所以 a
CS
可能是ThaiCat extends Cat
with argument"Siamese"
并且CK
可能是 aThaiCat extends Cat
with argument"Korat"
并且CB
可能是AmericaCat extends Cat
with argumentBengal
- 里面还有
data
String
其他信息。例如,它可能具有 Animal 的名称。不要担心如何解析这些数据,这段代码将在它们之间共享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>>
map绑定到一个工厂类中,并在创建后作为方法调用data
传入对象Cat
- 创建一个 AssistedInject 工厂,并让每个枚举的
makeCat
方法调用工厂中正确的方法。问题是,我无法将工厂注入 Enumeration 实例,Guice 建议不要使用静态注入。因此,我必须沿着方法链一路传递我的工厂,这似乎违背了目的。此外,这并不能解决不允许错误的 String 调用错误的构造函数的问题。 - 创建手动工厂对象。虽然我不确定工厂应该完成多少工作以及枚举(如果有的话)应该完成多少工作。
最好的解决方案是什么?