所以我正在构建一个游戏引擎,我需要能够从实现某个接口的类中调用方法(我只想调用接口实现的方法)。
我的问题是我不知道类名将实现它。
那么,例如,Java 如何在不知道类名的情况下在所有实现 Runnable 的类中调用 run() 方法?
所以我正在构建一个游戏引擎,我需要能够从实现某个接口的类中调用方法(我只想调用接口实现的方法)。
我的问题是我不知道类名将实现它。
那么,例如,Java 如何在不知道类名的情况下在所有实现 Runnable 的类中调用 run() 方法?
实际上,您是在询问工厂模式或依赖注入容器(例如 Spring)。
当然你可以调用接口上的方法,问题是你如何获取实例。当然,这必须在某处指定、编码或配置。如果将来可能有不止一个,配置是更可取的。
因此,更多的是一个真实的例子:
public interface MovementStrategy {
public Move selectMove (Actor actor, ActorSituation theirSituation);
}
public class MonsterTypes {
public static MonsterType GOBLIN = new MonsterType( "goblin", new AttackMover(1.2));
public static MonsterType TROLL = new MonsterType( "troll", new AttackMover(0.45));
public static MonsterType DEER = new MonsterType( "deer", new FleeMover(2.0));
// useful to have, also.
public static List<MonsterType> getAllRegisteredTypes();
public static class MonsterType {
protected String name;
protected MovementStrategy moveStrategy;
// TODO -- getters & setters for all properties.
// constructor.
public MonsterType (String name, MovementStrategy moveStrategy) {
this.name = name;
this.moveStrategy = moveStrategy;
}
}
}
public class AttackMover implements MovementStrategy {
// SPEC: generally move towards/attack PC, with varying speeds.
}
public class FleeMover implements MovementStrategy {
// SPEC: generally run away from PCs.
}
这可能不是一个完美的设计——它将“运动”(也就是寻找目标)与演员的整体转向/动作混为一谈——但希望它能给你更多的想法。
如果您只想从接口调用方法(很好!),那么您现在通常不需要实现者的名称。
getRunnableFromSomewhere().run();
始终有效并在该方法返回的实例上调用该run()
方法。
如果您想在运行时获得类名,请getClass().getName()
对实例进行简单调用:
System.out.println(getRunnableFromSomewhere().getClass().getName());
一个简单的Number
接口示例:
public class NumberExample {
public static void main(String[] args) {
MagicNumber magic = MagicNumberProvider.get(); // a random implementation
System.out.println(magic.getMagicNumber().doubleValue()); // We know nothing about the implementations
}
}
class MagicNumberProvider {
public static MagicNumber get() {
return Math.random() > 0.5d ? new ItsMagicOne() : new ItsMagicTwo();
}
}
interface MagicNumber {
public Number getMagicNumber();
}
class ItsMagicOne implements MagicNumber {
@Override
public Number getMagicNumber() {return new Long(1);}
}
class ItsMagicTwo implements MagicNumber {
@Override
public Number getMagicNumber() {return new Double(2.5);}
}
它只调用接口方法,从主方法的角度来看,我们不知道MagicNumber
使用了哪个实现(它是随机的)以及Number
我们实际调用该doubleValue()
方法的哪个实现。
如果我正确理解了您的问题,您似乎对多态性有所误解,您不需要知道实现接口的类型。
看下面的例子,只有一个类直接知道每个敌人的类型,初始化类。
import java.util.ArrayList;
import java.util.List;
public class SO18671999 {
public static interface Enemy {
public void Attack(Enemy other);
public String getName();
}
public static class Dragon implements Enemy {
String name = "Onyxia";
public void Attack(Enemy other) {
System.out.println(this.name + " attacks " + other.getName()
+ " for 10 dmg!");
}
public String getName() {
return this.name;
}
}
public static class Cerberus implements Enemy {
private String name;
private int dmg;
public Cerberus(String name, int dmg) {
this.name = name;
this.dmg = dmg;
}
@Override
public void Attack(Enemy other) {
System.out.println(this.name + " attacks " + other.getName()
+ " for " + this.dmg + " dmg!");
}
@Override
public String getName() {
return this.name;
}
}
public static class EnemyInitializer {
private List<Enemy> enemies;
public EnemyInitializer() {
enemies = new ArrayList<>();
enemies.add(new Dragon());
enemies.add(new Cerberus("CerberusHeadLeft", 10));
enemies.add(new Cerberus("CerberusHeadRight", 10));
enemies.add(new Cerberus("CerberusHeadCenter", 20));
}
public List<Enemy> getEnemies() {
return enemies;
}
}
public static class EnemyAttacker {
private EnemyInitializer eI = new EnemyInitializer();
public void startAttacking() {
List<Enemy> enemies = eI.getEnemies();
for (Enemy one : enemies) {
for (Enemy two : enemies) {
if (one == two)
continue;
one.Attack(two);
}
}
}
}
public static void main(String[] args) {
EnemyAttacker eAttacker = new EnemyAttacker();
eAttacker.startAttacking();
}
}
服务提供接口
您可以使用 java SPI(服务提供者接口),稍后实现 jars 通过它在清单中声明相同的服务。使用应用程序可以进行查找、迭代它们并选择一个。
一个例子是不同的 XML 解析器实现。
范围
对于您的情况,有一个 run 方法可能就足够了:
class GameRunner {
public static void mainEntry(MyGameInterface mgi) {
}
}
实施者可能会这样做
cöass ThirdPartyGame implements MyGameInterface {
}
GameRunner.mainEntry(new ThirdPartyGame());
带有java反射的插件
您可以使您的 ad-hoc、自定义插件机制,并使用 java 反射来实例化类。第三方 jar 必须放置在某个位置,即类路径中,如您的 jar 清单中所定义。某处定义的类:
String klazz = resBundle.getProperty("pluginClass");
Class<MyGameInterface> klazz = Cass<MyGameInterface>.forName(klazz);
MyGameInterface game = klazz.getConstructor().newInstance();