Question

So I'm building a game engine and I need to be able to call methods from a class that implements a certain interface(I only want to call methods implemented by the interface).

My problem is that I don't know what the class name will be implementing it.

So how does, for instance, Java call the run() method in all classes that implement Runnable without knowing the class name?

Was it helpful?

Solution

Really, you're asking about the Factory pattern or a dependency injection container such as Spring.

Of course you can call the methods on an interface, the question is how you get the instance. That of course has to be specified, coded or configured somewhere. Configuration is preferable if there could ever be more than one in the future.

Thus, more of a real example:

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

This isn't probably a perfect design -- it conflates "movement" (aka goal-seeking) with the actor's turn/actions overall -- but hopefully it gives you some more idea.

OTHER TIPS

If you only want to call methods from the interface (good!), then you usually don't need to now the name of the implementor.

getRunnableFromSomewhere().run();

always works and calls the run() method on the instance that is returned by that method.

If you want to now the class name at runtime, simpy call getClass().getName() on the instance:

System.out.println(getRunnableFromSomewhere().getClass().getName());

A simple example with the Number interface:

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);}
}

It only calls interface methods and we have, from the perspective of the main method, no idea, which implementation of MagicNumber is used (it's random) and on which implementation of Number we actually call the doubleValue() method.

If I understood your question correctly it seems you have slightly misunderstood polymorphism, you don't need to know the type that implements the interface.

See the following example, there is only one class that directly knows the types of each enemy, the initializing class.

  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();
    }

}

Service Provide Interface

You can use java SPI (Service Provider Interface) by which later implementing jars declare the same service in the manifest. A using app can do a lookup, iterate over them and pick one.

An example is the different XML parser implementations.

Parameter

For your case it might suffice to have a run method:

class GameRunner {
    public static void mainEntry(MyGameInterface mgi) {
    }
}

And the implementors may do

cöass ThirdPartyGame implements MyGameInterface {
}

GameRunner.mainEntry(new ThirdPartyGame());

Plugin with java reflection

You can make your ad-hoc, self-define plugin emchanism, and use java reflection to instantiate the class. The third party jar must be placed at some location, that is in the class path, as defined in your jar's manifest. The class somewhere defined:

String klazz = resBundle.getProperty("pluginClass");
Class<MyGameInterface> klazz = Cass<MyGameInterface>.forName(klazz);
MyGameInterface game = klazz.getConstructor().newInstance();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top