2

所以我正在构建一个游戏引擎,我需要能够从实现某个接口的类中调用方法(我只想调用接口实现的方法)。

我的问题是我不知道类名将实现它。

那么,例如,Java 如何在不知道类名的情况下在所有实现 Runnable 的类中调用 run() 方法?

4

4 回答 4

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.
}

这可能不是一个完美的设计——它将“运动”(也就是寻找目标)与演员的整体转向/动作混为一谈——但希望它能给你更多的想法。

于 2013-09-07T10:05:30.107 回答
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()方法的哪个实现。

于 2013-09-07T09:51:38.800 回答
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();
    }

}
于 2013-09-07T10:13:34.527 回答
0

服务提供接口

您可以使用 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();
于 2013-09-07T10:40:32.223 回答