在我的程序中,用户需要输入游戏将拥有的玩家类型。玩家为"human"
,"good"
(对于良好的AI),"bad"
(对于不良AI)和"random"
(对于随机AI)。这些玩家中的每一个都有自己的类,扩展了一个名为PlayerType
的抽象类。
我的目标是将String
映射到对象,这样我就可以A)使用String作为键的一种来创建一个新对象,并且B)从其子类的对象中获取相关的String
最终,我只希望隐式String
只在代码中出现一次,以便我可以在以后根据需要更改它而不进行重构。
我尝试过使用普通的HashMap,但通过值搜索键看起来很笨拙。此外,我猜测我必须使用getInstance()
的{{1}}方法,这种方法不那么笨重,如果它是唯一的方法就可以了。
答案 0 :(得分:4)
我要做的是创建一个enum
,它基本上可以作为给定类型的工厂。
public enum PlayerTypes {
GOOD {
@Override
protected PlayerType newPlayer() {
return new GoodPlayer();
}
},
BAD {
@Override
protected PlayerType newPlayer() {
return new BadPlayer();
}
},
RANDOM {
@Override
protected PlayerType newPlayer() {
return new RandomPlayer();
}
};
protected abstract PlayerType newPlayer();
public static PlayerType create(String input) {
for(PlayerTypes player : PlayerTypes.values()) {
if(player.name().equalsIgnoreCase(input)) {
return player.newPlayer();
}
}
throw new IllegalArgumentException("Invalid player type [" + input + "]");
}
)
因为那样你就可以这样称呼它:
String input = getInput();
PlayerTypes.create(input);
当然,你可以通过尝试再次获得输入来获得IllegalArgumentException
。
编辑:显然在这种特殊情况下,您可以仅用
替换该循环return PlayerTypes.valueOf(input).newPlayer();
它会做同样的事情。我倾向于匹配enum
中的其他构造函数参数,所以我没有考虑使用valueOf()
,但它绝对更清晰。
EDIT2:获取该信息的唯一方法是在PlayerType
类中定义一个抽象方法,该方法返回给定类型的PlayerTypes
枚举。
public class PlayerType {
public abstract PlayerTypes getType();
}
public class GoodPlayer extends PlayerType {
@Override
public PlayerTypes getType() {
return PlayerTypes.GOOD;
}
}
答案 1 :(得分:1)
我喜欢Epic提供的答案,但我找不到笨重的地图。因此,可以保留地图并直接获取构造函数。
Map<String, Supplier<PlayerType> map = new HashMap<>();
map.put("human", Human::new);
Human h = map.get("human").get();
答案 2 :(得分:0)
我能想到的两个主要选择:
正如您所提到的那样使用Class.newInstance()
(不确定您是否牢记这一点):
// Set up your map
Map<String, Class> classes = new HashMap<String, Class>();
classes.put("int", Integer.class);
classes.put("string", String.class);
// Get your data
Object s = classes.get("string").newInstance();
如果要使用带参数的构造函数(Class.getDeclaredConstructor),可以使用newInstance.example
。
另一种选择是使用switch
:
Object getObject(String identifier) {
switch (identifier) {
case "string": return new String();
case "int": return new Integer(4);
}
return null; // or throw an exception or return a default object
}
答案 3 :(得分:0)
一个可能的解决方案:
public class ForFunFactory {
private ForFunFactory() {
}
public static AThing getTheAppropriateThing(final String thingIdentifier) {
switch (thingIdentifier) {
case ThingImplApple.id:
return new ThingImplApple();
case ThingImplBanana.id:
return new ThingImplBanana();
default:
throw new RuntimeException("AThing with identifier "
+ thingIdentifier + " not found.");
}
}
}
public interface AThing {
void doStuff();
}
class ThingImplApple implements AThing {
static final String id = "Apple";
@Override
public void doStuff() {
System.out.println("I'm an Apple.");
}
}
class ThingImplBanana implements AThing {
static final String id = "Banana";
@Override
public void doStuff() {
System.out.println("I'm a Banana.");
}
}