Итак, в основном название звучит намного более привлекательно, чем реальный вопрос.
Я пишу приложение, в котором хотел бы реализовать систему достижений. Если у меня есть все мои достижения, созданные как экземпляры родового класса, как я могу написать метод для проверки этих достижений (то есть определить, достиг ли пользователь или превысил цели), когда тип совершенного умения может варьироваться, число условий может быть изменен, и тип проверки может отличаться?
Например:
Достижение - 10 000 очков!
Тип - итоговая сумма
Значение (X) - 10 000
Условия - 1
Валидация - больше X
против.
Достижение - Ультра-фрагмент
Тип - убивает
Значение (X) - 10
Тип - время
Значение (Y) - 10 секунд
Условия - 2
Валидация - по крайней мере X меньше Y
Я пытаюсь избежать hardcoding функции проверки для каждого достижения, поскольку они в основном являются обобщенными, и единственная разница заключается в том, как они проверяются.
Как класс достижений выглядит примерно так:
public class Achievement
{
boolean locked;
String name;
String desc;
public Achievement(string n, string d)
{
//ctor code
}
}
Я пытаюсь придумать способ сделать это без указателей функций, и я терплю неудачу. Кроме того, можете ли вы использовать указатели на функции в java? Im новое для языка: (
Я думаю, что правильный трек должен был бы иметь метод проверки для каждого Достижения:
public abstract class Achievement {
//...name, etc
public boolean isSatisfied(Data byPlayerData);
}
Но это не мешает вам предоставить несколько конкретных реализаций и настроить их с параметрами.
public class ZombieKillingAchievement extends Achievement {
private final int numKills;
public ZombieKillingAchievement(String name, int numKills) {
this.numKills = numKills;
}
public boolean isSatisfied(Data userData) {
return userData.getZombieKills() >= numKills;
}
}
//...
registerAchievement(new ZombieKillingAchievement("Zombie Master", 100));
registerAchievement(new ZombieKillingAchievement("Zombie Tamer", 50));
//... on user data change
for ( Achievement a : registeredAchievements ) {
if ( a.isSatisfied() ) {
//show congratulatory message
}
}
EDIT Другим вариантом предотвращения наследования (и использования композиции) является использование чего-то похожего на шаблон стратегии .
public class Achievement {
//...name, etc
private final AchievementValidator validator;
}
public interface AchievementValidator {
public boolean isSatisfied(Data userData);
}
При использовании с анонимными внутренними классами он в значительной степени использует указатели на функции
registerAchievement(new Achievement("Zombie Killer", new AchievementValidator() {
public boolean isSatisfied(Data data) { return data.getZombieKills() >= 50; }
});
Указатели функций в Java (и вообще на любом объектно-ориентированном языке) обычно заменяются полиморфными объектами.
О том, что я не жестко кодировал валидацию, я не думаю, что стоит написать для этого механизм правил, усилия будут намного выше. То, что вы можете сделать, - унифицировать достижения того же типа, что и объекты того же класса, с полем, имеющим разные значения пороговых значений.