Создание общего расширения абстрактного класса - PullRequest
1 голос
/ 05 октября 2011

Попытка написать некоторый обобщенный код для Генетических Алгоритмов, и у меня есть абстрактный класс Genotype следующим образом:

public abstract class Genotype {
private ArrayList<Gene> genotype = new ArrayList<Gene>();

//...

public Genotype(ArrayList<Gene> genotype) {
    setGenotype(genotype);
    setGenotypeLength(genotype.size());
}

public abstract Phenotype<Gene> getPhenotype();

public abstract void mutate();

//...
}

Этот класс предназначен для расширения, и подкласс, очевидно, обеспечивает реализацию getPhenotype () имутируют ().Однако у меня также есть второй класс, который принимает два объекта Genotype в качестве параметров и возвращает ArrayList, содержащий объекты Genotype.Поскольку на данный момент я не знаю тип расширенных объектов Genotype, мне нужно использовать универсальный параметр следующим образом:

public class Reproducer {

//...

    private <G extends Genotype> ArrayList<Genotype> crossover(G parent1, G parent2) {
        ArrayList<Genotype> children = new ArrayList<Genotype>();

        ArrayList<Gene> genotypeOne = ArrayListCloner.cloneArrayList(parent1.getGenotype());
        ArrayList<Gene> genotypeTwo = ArrayListCloner.cloneArrayList(parent2.getGenotype());

        //one point crossover
        int p = gen.nextInt(genotypeOne.size());

        for (int i = 0; i < p; i++) {
            genotypeOne.set(i, genotypeOne.get(i));
            genotypeTwo.set(i, genotypeTwo.get(i));
        }
        for (int i = p; i < 10; i++) {
            genotypeOne.set(i, genotypeTwo.get(i));
            genotypeTwo.set(i, genotypeOne.get(i));
        }

        children.add(new G(genotypeOne)); //THROWS ERROR: Cannot instantiate the type G
        children.add(new G(genotypeTwo)); //THROWS ERROR: Cannot instantiate the type G

        return children;
    }
}

Однако, поскольку мне нужно вернуть два объекта типа G в ArrayListУ меня явно есть проблема, когда я не могу создать экземпляры новых объектов Genotype, потому что они 1. универсальные типы и, предположительно, 2. абстрактные.

Это может быть плохой способ работать вместе, но если кто-тоесть решение, которое было бы здорово.Спасибо.

Ответы [ 2 ]

3 голосов
/ 05 октября 2011

Я бы предложил использовать фабричный метод в вашем Genotype классе

public abstract class Genotype {
     public abstract GenoType newInstance();
}
1 голос
/ 05 октября 2011

Вы можете использовать абстрактный фабричный шаблон .Поскольку вам нужен только один фабричный метод на вашей фабрике, это, возможно, вырожденный случай, но это может быть то, что вам нужно.Вы должны передать экземпляр фабрики вашему Reproducer объекту, вероятно, в качестве аргумента какого-либо метода.Это не красиво, но, по крайней мере, теперь у вас есть абстракция по созданию объектов.

Лучшим решением, вероятно, будет изменение вашей архитектуры.Почему бы не забыть о классе Genotype?Ваше представление генотипа - это в основном список генов.Вы можете создать служебный класс с (общими) операциями в этих списках и использовать эти операции в других ваших классах.Ниже приведен набросок того, что я имею в виду:

public static <G extends Gene> List<? extends G> mutate( List<G> genotype ) { ... }
public static <G extends Gene> List<List<? extends G>> crossover( List<G> p1, List<G> p2 ) { ... }

В качестве примечания: отдавайте предпочтение объявлению типов интерфейса над типами классов;в вашем примере вы не используете интерфейс List.

В качестве последнего примечания: в вашем примере вам не нужен универсальный тип.Если вы объявите типы параметров как Genotype, вы получите то же решение (с той же проблемой).Параметр типа X принимает любой объект типа X (включая подтипы!) В качестве аргумента.

...