Search code examples
javaclassreflectionpolymorphismcommand-pattern

What is the best way to instantiate a class using Reflection with the polymorphism?


I'm trying to use Reflection in java to
instantiate a Player with a Command Pattern likes below :

There is only one 'execute' method in a Command class,
And the InitiatePlayerCommand as its name , it will instantiate a
subclass of Player according to the playerClass passed in the constructor.

I have two kind of subclass of Player class : HumanPlayer and AiPlayer for polymorphism.

I expect it will instantiate one of them subclass and add into the playerList

but I have no idea what is the best way to reach this with Reflection. It always occurs a typecast error .

public class InitiatePlayerCommand implements Command{
private List<Player> playerList;
private String name;
private WarMode warMode;
private Class<?> playerClass;
public <T extends Player> InitiatePlayerCommand(String name, WarMode mode ,List<Player> list
        ,Class<T> playerClass){
    this.name = name;
    this.warMode = mode;
    this.playerList = list;
    this.playerClass = playerClass;
}

@Override
public void execute() throws InstantiationException, IllegalAccessException, IllegalArgumentException, NoSuchFieldException, SecurityException {
    Player player = (Player) playerClass.newInstance();
    player.setName(name);
    player.setWarMode(warMode);
    playerList.add(player);
}

public static void main(String[] argv){
    List<Player> playerList = new ArrayList<Player>();
    new InitiatePlayerCommand("Johnny",WarMode.MILITARY,playerList,HumanPlayer.class)
            .execute();  // this line get an error HumanPlayer.class isn't compatible to Class<T extends Player> playerClass
    System.out.println(playerList);

}

}

Is there any way to reach this without using Class<?>


Solution

  • You should consider using a Supplier<T>, which is a no-arg function that returns an object.

    In this case, your Supplier might be defined like this:

    Supplier<Player> playerSupplier = () -> new HumanPlayer();
    

    You can then use it like this:

    public void execute() {
        Player player = playerSupplier.get();
        player.setName(name);
        player.setWarMode(warMode);
        playerList.add(player);
    }