Прежде всего, вам необходимо решить, будет ли поведение разных персонажей действительно настолько дифференцированным, как необходимость в Java-коде для реализации конкретного поведения.Возможно, поведение может быть выражено одним классом и изменено только путем установки различных значений таких параметров, как скорость, здоровье, сила атаки и т. Д. В этом случае вы полностью избавитесь от проблемы наследования и будете использовать один класс, в то время как пользователи будут толькопредоставить различные конфигурации.
Теперь, если вам действительно нужно очень нестандартное поведение и загрузка пользовательских классов Java, я вижу два основных решения.
Первое - стандартное.Это использует только немного отражения.Вы определяете интерфейс, например:
public interface C {
void control(); //Params skipped for brevity
}
Теперь ваши пользователи создают классы, которые реализуют этот интерфейс.Единственная проблема заключается в том, как создать экземпляр класса игрока.Получив его, вы вызываете его control()
или другие методы через интерфейс.Во-первых, пользователи должны сделать этот класс загружаемым.Это можно сделать через сеть или другими сложными способами, но самое простое - они помещают свой файл .class
или .jar
в путь к классам при запуске приложения.Теперь все, что вам нужно, это создать экземпляр класса.Предполагая, что вы указываете требование, чтобы класс имел конструктор с нулевым аргументом (вы можете определить метод в вашем интерфейсе для загрузки некоторой конфигурации и выполнить инициализацию позже), вы будете делать что-то вроде:
C gameCharacter = (C)Class.forName("your.fully.qualified.ClassName").newInstance();
Помимо обработки ошибок, это все, что вам нужно.Теперь вы можете вызывать все методы интерфейса C
для вашего gameCharacter
объекта - не зная, кто или как его написал и что именно методы делают.
Другое решение будет использовать Groovy или другой подобный язык для компиляции и запуска кода на лету.В этом случае вам не нужен пользовательский JAR в пути к классам, и вы даже можете обойти необходимость знать имя класса для загрузки.Ваш пользователь может предоставить Java-код метода control()
в виде текста, и вы можете иметь класс-заглушку, метод control()
которого компилирует и выполняет только Groovy-код, предоставленный пользователем.Это может быть более удобным, но требует, чтобы пользовательский код символа был предоставлен вам как исходный код, а не скомпилированный JAR, что может быть проблемой для некоторых пользователей.Кроме того, это решение более удобно, если реализации будут короткими и автономными, в то время как отдельный JAR и загрузка через отражение лучше, если загруженный код более сложен, использует вспомогательные классы, кроме основного и т. Д.