使用命令行创建新对象

时间:2015-09-16 16:54:28

标签: java

在我的程序中,用户需要输入游戏将拥有的玩家类型。玩家为"human""good"(对于良好的AI),"bad"(对于不良AI)和"random"(对于随机AI)。这些玩家中的每一个都有自己的类,扩展了一个名为PlayerType的抽象类。

我的目标是将String映射到对象,这样我就可以A)使用String作为键的一种来创建一个新对象,并且B)从其子类的对象中获取相关的String

最终,我只希望隐式String只在代码中出现一次,以便我可以在以后根据需要更改它而不进行重构。

我尝试过使用普通的HashMap,但通过值搜索键看起来很笨拙。此外,我猜测我必须使用getInstance()的{​​{1}}方法,这种方法不那么笨重,如果它是唯一的方法就可以了。

4 个答案:

答案 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.");
    }

}