2010-10-11 2 views
1

Скажите, что у вас есть класс Население и население составляют внутренний список лиц. Пользователь хочет передать незавершенный индивидуальный подкласс Population и позволить Population выполнять работу по их созданию, независимо от того, какой подкласс был передан.Как разрешить классу создавать другие классы, когда эти другие классы передаются пользователем?

public class Population{ 

    private List<Individual> indiList = new ArrayList(25); 


    /*I know this won't work for multiple reasons, but shows the idea*/ 
    public void addIndividualsOfType(Individual individual){ 

    for (ListIterator it = indiList.listIterator(); it.hasNext();){ 
     it.next() 
     it.add(individual.construct(param1, param2, param3); 
    } 
    } 

} 

    public abstract class Individual{ 
    SomeType param1; 
    ... 

    public Individual(SomeType param1, SomeType param2, SomeType param3){ 
    this.param1 = param1; 
    ... 
    } 
} 

    public class HappyIndividual extends Individual{ 
    ... 
    } 

    public class SadIndividual extends Individual{ 
    ... 
    } 

Я хотел бы быть в состоянии сделать вызов, как population.addIndividualsOfType(HappyIndividual)

Очевидно, что этот код не будет работать по многим причинам (например, пропускание uninstantiated класса). Я просто пытаюсь проиллюстрировать идею того, что я хочу делать, это не вопрос о том, почему приведенный выше код не работает. Я знаю, что это не сработает, поэтому я не могу понять, как это можно сделать.

Я весь день занимаюсь строителями и статическими фабричными методами. Проблема в том, что мы говорим о подклассах здесь. Подклассы не очень хорошо работают со Static. Если я дам Индивидуальному статическому заводскому методу, я в конечном итоге создаю Индивидуумов, а не Счастливых Индивидуумов. Аналогичные проблемы возникают с Builder. Я также хочу, чтобы это не было слишком сложным.

Я чувствую, что это должно быть очень легко, но у меня проблемы. Благодарю.

ответ

1

Есть по существу два способа сделать это:

Вы можете продолжить вниз ваш текущий путь и использовать отражение для построения классов:

public void addIndividualsOfType(Class<? extends Individual> clazz){ 
    for (ListIterator it = indiList.listIterator(); it.hasNext();){ 
     it.next() 
     it.add(clazz.newInstance()); // using no-args constructor 
    } 
} 

и использовать конструктор с аргументами вы бы заменить it.add(clazz.newInstance()) с чем-то вроде этого:

Constructor<? extends Individual> cons = clazz.getConstructor(
     param1.getClass(), param2.getClass(), param3.getClass()); 
    it.add(cons.newInstance(param1, param2, param3)); 

(. Я ушел из обработки исключений ... но вы получите картину)

Однако, лучший подход будет заключаться в том, чтобы реорганизовать ваш код так, чтобы вы передали объект фабрики, а не объект Class.Например:

public interface IndividualFactory { 
    public Individual create(T1 p1, T2 p2, T3 p3); 
} 

public static final IndividualFactory TALL_FACTORY = new IndividualFactory() { 
    public Individual create(T1 p1, T2 p2, T3 p3) { 
     return new TallIndividual(p1, p2, p3); 
    } 
}; 

public void addIndividualsOfType(IndividualFactory factory){ 
    for (ListIterator it = indiList.listIterator(); it.hasNext();){ 
     it.next() 
     it.add(factory.create(param1, param2, param3); 
    } 
} 

Обратите внимание, что решение на заводе может быть подвергнуто статическому контролю. Напротив, отражающая версия должна иметь дело с несколькими исключениями времени выполнения, связанными с типом.

+0

Я знаю, что фабрики рекомендуются для отражения. Зачем? –

+1

@Ben B - фабрики более надежны, чем решение на основе отражения, поскольку они статически проверяются по типу. Если есть ошибки, связанные с типом, они, вероятно, будут собраны во время компиляции. Отражение также происходит медленнее, поскольку проверка типов выполняется повторно во время выполнения, а не один раз во время компиляции. –

+0

В коде есть что-то очень неправильное. Я думаю, что у меня есть то, что вы пытались написать ... но вы можете это очистить. –

1

Я хотел бы иметь возможность сделать вызов, как population.addIndividualsOfType (HappyIndividual)

Вы были совсем близко, когда вы просили, чтобы сделать это. Вместо этого вы можете передать HappyIndividual.class, который является объектом класса, представляющим класс HappyIndividual. Сам этот объект имеет тип Class, который представляет класс во время выполнения.

Ваш метод будет выглядеть следующим образом:

public void addIndividualsOfType(Class<? extends Invididual> clazz) { 
    for (ListIterator it = indiList.listIterator(); it.hasNext();){ 
     it.next(); 
     it.add(clazz.newInstance()); 
    } 
} 

Вызов newInstance предполагает, что ваш класс имеет конструктор по умолчанию без параметров. В противном случае вам нужно использовать метод getConstructor для получения конкретного конструктора, а затем вызвать newInstance на этом конструкторе с правильными параметрами.

+0

Ударьте мне это ... +1 для класса clazz' вместо 'addIndividualsOfType (класс clazz)' –

0

Пропустите в рассматриваемом классе (например, HappyPerson.class) и получите конструктор, позвонив Class.getConstructor(arg...), а затем создайте экземпляр экземпляра.

Смежные вопросы