2016-06-10 2 views
3

У меня есть базовый класс под названием Enemy и различные подклассы, которые типа Enemy, такие как BigEnemy, LazerEnemy, AvoidingEnemy и т.д.Выбор подкласса без переключателя заявления в Java

У меня есть Formation класс, цель которого заключается в создании специализированные формирования врагов, такие как линия, сетка, пирамида.

Я хотел бы, чтобы формация взяла в качестве параметра какой тип подкласса врага, которого я хочу создать.

Formation f = new Formation("LazerEnemy","triangle", 4); // makes a triangle formation of lazer enmies 
Formation f = new Formation("BigEnemy","line", 10); // makes a line of big enemies 

В настоящее время я собирался сделать что-то вроде передать строку с именем enemyType (или это может быть просто целым числом и не переключаться заявления), но так как у меня есть так много типов врагов мне было интересно, если там был аккуратнее способ передать тип объекта, который я хочу создать, который не должен использовать оператор switch.

Возможно, это имеет какое-то отношение к Factory и this вопросу, но я не совсем понимаю.

Благодаря

+0

Почему вы не можете передать непосредственно в 'новый LazerEnemy()' или 'новый BigEnemy()', где 'Formation' конструктор принимает' Enemy' как первый параметр? – Tunaki

+0

У вас есть три варианта: 1) использовать условный выключатель для балансировки или if-else, 2) использовать отражение и пройти в классе, например. LazerEnemy.class, 3) имеют разные заводские методы, например. Formation.createBigEnemy («строка», 10); – bhspencer

+0

@Tunaki Итак, вы говорите, передайте объект подкласса в качестве параметра Formation like Formation (новый LazerEnemy(), «пирамида», 4), а затем конструктор Formation сделает что? Мне нужно создать несколько новых типов Enemy. Формирование (Enemy e, string ftype, int number) {}. Мне нужно создать несколько врагов. Должен ли я быть клонирующим? – user3772547

ответ

0

Вы должны решить путем создания интерфейса Enemy Factory, а затем конкретные случаи EnemyFactories для всех ваших типов врагов. Затем используйте его как

+1

Это должен быть комментарий, а не ответ. – bhspencer

+1

@bhspencer Почему? Он отвечает на вопрос, а не комментарии о том, как его спрашивали. –

+0

Я согласен и приложил некоторую работу, чтобы сделать ваш ответ более наглядным. Я знаю, что вы пытаетесь сказать ему, но есть много Java-заводов, почему бы не показать близкий к соответствующему примеру, как ... [реализация-factory-design-pattern-in-java] (http://howtodoinjava.com/ design-patterns/creation/implementation-factory-design-pattern-in-java /) – Underbalanced

1

Существует множество способов его устранения. Один из них использует Dependency Inversion principle. То есть вызывающие в new Formation() конструкторе может создавать враг тоже:

Formation f1 = new Formation(new LazerEnemy(), "triangle", 4); 
Formation f2 = new Formation(new BigEnemy(), "line", 10); 

Если эти враги имеют длинные конструкторы, то вы могли бы использовать рамки Injection зависимостей. Google guiceотносительно легко настроить.

-1

Я, вероятно, поеду с заводским методом.

Class A 

Class B extends A 

Class C extends A 

public static A factory(string) 
    if(string.equal("b")) return new B 
    if(string.equal("c")) return new C 

Этот псевдокод может быть немного грубым по краям, но он должен получить точку поперек.

4

Если я правильно понимаю, конструктор Formation должен иметь возможность создавать несколько экземпляров данного типа врага. Вместо того чтобы передавать тип врага в виде строки или как класс, вы должны просто дать своему формированию пути создать враг, т.е. завода или поставщика врагов:

public clas Formation<E extends Enemy> { 

    // we'll store them in a list 
    private List<T> enemies; 

    public Formation(Supplier<E> enemySupplier, int count) { 
     enemies = new ArrayList<>(); 
     for (int i = 0; i < count; i++) { 
      enemies.add(enemySupplier.get()); 
     } 
    } 
} 

затем вы можете создать формирование LazerEnemy таким образом, если LazerEnemy имеет конструктор без аргументов:

Formation<LazerEnemy> f = new Formation<>(LazerEnemy::new, 10); 

Пусть конструктор LazerEnemy нуждается в силе своего лазерно, вы бы использовать

int strenth = 5; 
Formation<LazerEnemy> f = new Formation<>(() -> new LazerEnemy(strength), 10); 

Итак, позвольте собеседнику решить и указать, как должны создаваться враги в формировании, а не заставлять Формирование знать, как создавать все виды врагов.

+0

Да, это хороший способ сделать это: он отделяет логику. «Формирование» несет ответственность за создание врагов. Он не несет ответственности за создание врагов; его цель - упорядочить их в правильном образовании. – Tunaki

+0

Пара вопросов. Наверху у вас есть Formation . Я использую generics, когда я использую arraylists n такой, но что здесь происходит? Что такое E? Второй .. Является ли поставщиком класс, который я должен сделать? На что это похоже? Получает ли метод get только новый объект Enemy? В-третьих, я видел оператора двойной толстой кишки раньше, но я не знаю, что это значит. Я не использую Java 8 прямо сейчас. Я еще не видел стрелку. – user3772547

+0

E - тип врагов в составе. Если вам это не нужно, вы можете сделать свой класс неэквивалентным. Но если вам нужно вывести врагов из своего образования и узнать, какой у них тип, то ваш тип должен быть общим. Это имеет смысл: если я правильно понимаю, Formation - это совокупность врагов, как и список. E - тип врагов, содержащихся в пласте. [Поставщик] (https://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.html) является интерфейсом JDK. Вы можете сделать еще один, но Поставщик хорошо подходит. –

2

Вы можете передать тип методу в качестве аргумента.

Formation f = new Formation(LazerEnemy.class, Shape.LINE, 4) 

public formation(Class<? extends Enemy> enemyType, Shape shape, int num) { 
    Enemy enemy1 = enemyType.newInstance(); 
    ... 
} 

Вы будете нуждаться в try хотя

+1

Я печатал это, когда вы его разместили! Благодаря :). Ему также понадобится петля и какой-то способ собрать врагов. Он мог создать фабрику статического класса в Enemy.class, которая возвращает врага или врагов. Также ему, возможно, придется использовать метод Constructor для newInstance, если он хочет, чтобы параметры были переданы врагам. – Underbalanced