所以我正在构建一个游戏引擎,我需要能够从实现某个接口的类调用方法(我只想调用接口实现的方法)。
我的问题是我不知道类名会实现什么。
那么,例如,Java如何在不知道类名的情况下调用实现Runnable的所有类中的run()方法?
答案 0 :(得分:2)
真的,你问的是工厂模式或依赖注入容器,比如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.
}
这可能不是一个完美的设计 - 它将“运动”(又名追求目标)与演员的转向/动作整体混为一谈 - 但希望它能给你一些更多的想法。
答案 1 :(得分:1)
如果你只想从界面调用方法(好!),那么你现在通常不需要实现者的名字。
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()
方法。
答案 2 :(得分:0)
如果我正确地理解了你的问题,你似乎有点误解了多态性,你不需要知道实现接口的类型。
参见下面的例子,只有一个类直接知道每个敌人的类型,即初始化类。
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();
}
}
答案 3 :(得分:0)
服务提供界面
您可以使用java SPI(服务提供程序接口),稍后实现jar会在清单中声明相同的服务。使用应用程序可以进行查找,迭代它们并选择一个。
一个例子是不同的XML解析器实现。
的参数强> 的
对于你的情况,有一个run方法就足够了:
class GameRunner {
public static void mainEntry(MyGameInterface mgi) {
}
}
实施者可能会这样做
cöass ThirdPartyGame implements MyGameInterface {
}
GameRunner.mainEntry(new ThirdPartyGame());
使用java反射插件
您可以制作临时的自定义插件机制,并使用java反射来实例化该类。第三方jar必须放在某个位置,即在jar路径中定义的类路径中。某处定义的类:
String klazz = resBundle.getProperty("pluginClass");
Class<MyGameInterface> klazz = Cass<MyGameInterface>.forName(klazz);
MyGameInterface game = klazz.getConstructor().newInstance();