у меня есть метод
private void positionMagican() {
int x;
int y;
boolean magicanIsCreated;
magicanIsCreated = false;
while (!magicanIsCreated){
x = random.nextInt(sizeX);
y = random.nextInt(sizeY);
if (field.getFieldable(x,y) instanceof Empty){
mag = new Magician(x,y,sizeX,sizeY,field,player,this);
field.setFieldable(x,y,mag);
magicanIsCreated = true;
}
}
}
И точно такие же методы, только вместо Магикана змея, бочки и т.д.
Вот пример
private void positionGoblin() {
int x;
int y;
boolean goblinIsCreated;
goblinIsCreated = false;
while (!goblinIsCreated){
x = random.nextInt(sizeX);
y = random.nextInt(sizeY);
if (field.getFieldable(x,y) instanceof Empty){
goblin = new Goblin(x,y,player,field,this,sizeX,sizeY);
field.setFieldable(x,y,goblin);
goblinIsCreated = true;
}
}
} ```
Здесь различия только в классе объекта и в его параметрах, из-за этого в проекте много одинаковых методов, и я не понимаю, как создать один метод, в который можно было бы ввести нужный параметр. Можно ли создать метод, объединяющий эти методы? Я не понимаю. Как обеспечить создание объекта нужного класса с нужными параметрами.
Предположительно, все эти классы реализуют общий интерфейс? Как это называется? Т.е. какой тип третьего параметра setFieldable
?
все они используют один интерфейс, а третий параметр — объект для двумерного массива интерфейса Cell.
Оберните свои конструкторы в единый интерфейс.
Конструкторы Magician и Goblin принимают параметры в разном порядке, но это нормально, потому что это одна из проблем, которую может решить интерфейс:
private interface CharacterGenerator {
GameCharacter createCharacter(int x,
int y,
int sizeX,
int sizeY,
Field field,
Player player,
Game game);
}
(Я предполагаю, что Маг и Гоблин наследуют общего родителя, либо общий суперкласс, либо общий интерфейс, который я для примера назвал GameCharacter
.)
Я решил использовать порядок, соответствующий конструктору Magician, но это не имеет значения, поскольку каждая реализация этого интерфейса может поступать с конструкторами по своему усмотрению, включая их переупорядочение:
private static class MagicianGenerator
implements CharacterGenerator {
@Override
public GameCharacter createCharacter(int x,
int y,
int sizeX,
int sizeY,
Field field,
Player player,
Game game) {
return new Magician(x, y, sizeX, sizeY, field, player, game);
}
}
private static class GoblinGenerator
implements CharacterGenerator {
@Override
public GameCharacter createCharacter(int x,
int y,
int sizeX,
int sizeY,
Field field,
Player player,
Game game) {
return new Goblin(x, y, player, field, game, sizeX, sizeY);
}
}
Теперь вы можете создать один метод позиционирования вместо двух методов и передать объект, реализующий FeatureGenerator, этому одному методу позиционирования:
private void positionCharacter(CharacterGenerator generator) {
while (true) {
int x = random.nextInt(sizeX);
int y = random.nextInt(sizeY);
if (field.getFieldable(x,y) instanceof Empty) {
GameCharacter c = generator.createCharacter(
x, y, sizeX, sizeY, field, player, this);
field.setFieldable(x, y, c);
break;
}
}
}
И этот метод будет вызываться с использованием одного из этих вызовов:
positionCharacter(new MagicianGenerator());
positionCharacter(new GoblinGenerator());
Обратите внимание, что я удалил вашу логическую переменную «create». Вам это не нужно. Просто используйте break
, чтобы выйти из цикла.
Как отмечали другие, вы могли бы сделать это гораздо более кратким, если бы конструктор Magician и конструктор Goblin принимали одни и те же аргументы в точно таком же порядке, поскольку это позволило бы вам рассматривать интерфейс CharacterGenerator как функциональный интерфейс, и это позволит вам использовать ссылки на методы вместо явных классов реализации:
positionCharacter(Magician::new);
positionCharacter(Goblin::new);
Это сложный код, но этот вопрос и этот ответ можно считать ярким примером того, почему в последние годы люди чрезмерно склоняются к функциональному программированию и слепой критике ООП. Проще говоря, то, что должно быть рефакторингом для одного метода с добавленным параметром (будь то enum
или даже boolean
— это не тот случай) и проверкой if для создания Goblin
или Magician
, усложнено различными ненужными функциями языка и шаблонами псевдопроектирования. Это всего лишь мои два цента. Это противоположность KISS, это KICKME или Keep It Complication Keep Me Employed.
@Yamin Аргумент перечисления — разумная идея, если к нему не собираются добавлять дженерики. А если вы придумываете оператор switch
или серию операторов if-else, он не будет особенно масштабируемым, если в игре будет 70 типов персонажей.
VGR спасибо за этот шедевральный код ( ͡° ͜ʖ ͡°)
@Yamin Извините, но у меня слишком много игровых объектов, чтобы обрабатывать каждый отдельно.
@Yamin Я не вижу здесь никакой «слепой критики ООП»? Фабрика — это довольно стандартный шаблон ООП, и она гораздо лучше подходит для этого, чем параметр перечисления.
Передайте фабричную функцию в качестве обратного вызова, например
Magician::new
,Goblin::new
и т. д. Убедитесь, что все они принимают одни и те же параметры в одном и том же порядке.