2011-02-05 4 views
1

Я работаю над эволюционной имитационной моделью, реализованной на Java, и столкнулся с проблемой дизайна объектной ориентации, которую я, похоже, не сработал. Проблему можно резюмировать следующим образом:Java Generic Container Class

У меня есть базовый абстрактный плеер класса и два конкретных подклассов, связист и приемник:

abstract class Player 
{ 
    Strategy[] strategies; 
    double fitness; 
    ... 
} 

class Signaller extends Player 
{ 
    double quality; 
    .... 
} 

class Receiver extends Player 
{ 
    double[] weights; 
    int chosenChannel; 
    .... 
} 

Теперь мне нужно классы, которые представляют коллекции Связисты и приемников, и я ограничен для использования массивов для их хранения. Существуют методы, общие для обоих типов населения, но также специальные методы для сигнальных групп населения или для населения-получателя.

Концептуально, мне нужно что-то вроде этого:

abstract class Population 
{ 
    Player[] members; 

    void mixUpPopulation() {...} 
    Strategy[] getMeanStrategies() {...} 
    double getMeanFitness() {...} 
    ... 
} 

class SignallerPopulation extends Population 
{ 
    Signaller[] members; 
    ... 
} 

class ReceiverPopulation extends Population 
{ 
    Receiver[] members; 

    double[] getChannelPreferences() {...} 
    ... 
} 

Я думал о двух основных способов достижения этой цели:

  1. Have иерархию классов, как описано выше.
    Задача: Как может Player[] в суперклассе, а также Signaller[] или Receiver[] в подклассах относятся к одной и той же коллекции объектов?

  2. Сделать базовый класс родовое:

class Population <T extends Player> 
{ 
    ...  
    T[] members = (T[])new Object[popSize]; 
} 

Проблема: Как реализовать методы, специфичные для каждого из типов населения?

Я был бы признателен вам за понимание этих проблем или предложения других способов решения проблемы.

+2

массивы и дженерики вызовут проблемы, я думаю. попытайтесь скомпилировать предложенный второй оператор ... почему бы не использовать ArrayList ? – Karussell

+2

** Я вынужден использовать массивы для их хранения ** - почему? –

+0

Привет, Алекс. Если вы его решили, можете ли вы опубликовать рабочий пример. Если вам трудно понять этот пример, ваша оценка будет оценена по достоинству. – Deepak

ответ

2

Вы можете использовать дизайн 1 как в своем вопросе, но вместо хранения массива в абстрактном базовом классе вы добавите абстрактный защищенный метод (например, getMembers()), который будет реализован в подклассах, чтобы вернуть фактический массив как массив игроков.

В качестве альтернативы, вы можете сделать это абстрактный базовый класс родовым, и получить подклассы с соответствующими типами:

abstract class Population<T extends Player> 
{ 
    T[] members; 

    void mixUpPopulation() {...} 
    Strategy[] getMeanStrategies() {...} 
    double getMeanFitness() {...} 
    ... 
} 

class SignallerPopulation extends Population<Signaller> 
{ 
    public SignallerPopulation(int popSize) { members = new Signaller[popSize]; } 
    ... 
} 

class ReceiverPopulation extends Population<Receiver> 
{ 
    public ReceiverPopulation(int popSize) { members = new Receiver[popSize]; } 
    double[] getChannelPreferences() {...} 
    ... 
} 
+0

В этом случае T [] по-прежнему необходимо управлять (по крайней мере, экземпляром) подклассами, поскольку вы не можете создать массив общего типа (без использования Reflection и unchecked casts afterwards). –

+0

Я отредактировал свой ответ, чтобы показать, как можно создать массив. – Medo42

+0

Я решил пойти с первым вариантом, и предложение, которое вы сделали (с абстрактным методом в суперклассе), отлично работало. Я дам эскиз моего кода в ответе ниже. Большое спасибо за помощь. – Alex

1

Удалить members из Population и добавить абстрактную геттер-метод для членов к нему (public abstract Player getMember(int i) и public abstract int getNumPlayers() или что-то подобное). Подклассы необходимы для реализации геттера. Таким образом, вы по-прежнему будете иметь доступ к Player частям XYPopulation пользователей в Population.

+0

Спасибо за ваше предложение (в основном, тот же, что и первый вариант, предложенный @ Medo42). Я использовал его, и он отлично работает. – Alex

0

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

abstract class Population 
{ 
    protected abstract Player[] getMembers(); 
    protected abstract void setMembers(Player[] members);  

    void mixUpPopulation() {...} 
    Strategy[] getMeanStrategies() {...} 
    double getMeanFitness() {...} 
    ... 
} 

class SignallerPopulation extends Population 
{ 
    Signaller[] members; 

    protected Player[] getMembers() 
    { 
     return this.members; 
    } 

    protected void setMembers(Player[] members) 
    { 
     this.members = (Signaller[]) members; //required cast 
    } 
    ... 
} 

class ReceiverPopulation extends Population 
{ 
    Receiver[] members; 

    protected Player[] getMembers() 
    { 
     return this.members; 
    } 

    protected void setMembers(Player[] members) 
    { 
     this.members = (Receiver[]) members; //required cast 
    } 

    double[] getChannelPreferences() {...} 
    ... 
}