How to define/implement this interface with generics in a simpler way?
I'm working in a Genetic Algorithm and I want it as abstract as possible to be able to reuse the GA. I defined and implemented a Population 开发者_开发技巧Interface, and well it works, but I'm sure that's not the best way to do it. I don't have great experience with Java Generics. Is there an easier way of defining and implementing the Population interface (e.g. maybe avoid a cast conversion? avoid a new list in getChromosomes() ?)
public interface Population
{
void addChromosomes(List<? extends Chromosome> chromosomes);
List<Chromosome> getChromosomes();
// More code here ...
}
public class TSPPopulation implements Population
{
private List<TSPChromosome> chromosomes;
@Override
public void addChromosomes(List<? extends Chromosome> chromosomes) {
for (Chromosome chromosome : chromosomes) {
this.chromosomes.add((TSPChromosome) chromosome);
}
}
@Override
public List<Chromosome> getChromosomes() {
List<Chromosome> newList = new ArrayList<Chromosome>();
for (TSPChromosome chromosome : chromosomes) {
newList.add(chromosome);
}
return newList;
}
}
Use a Bounded Wildcard in your interface:
public interface Population<T extends Chromosome>{
void addChromosomes(List<T> chromosomes);
List<T> getChromosomes();
}
public class TSPPopulation implements Population<TSPChromosome>
{
private List<TSPChromosome> chromosomes;
@Override
public void addChromosomes(List<TSPChromosome> chromosomes) {
...
}
@Override
public List<TSPChromosome> getChromosomes() {
...
}
}
The simplest solution is extending a list (then use addAll(...)
to add a list of Chromosoms to the list):
class Population<T extends Chromosome> extends ArrayList<T> {
}
But if you want the same structure I would make Population
into a generic list class. That way both add...
and get...
methods can be handled in the generic base class. If you do want to override any other feature you just extend Population
(class TSPPopulation extends Population<TSPChromosome>
.
Usage:
public static void main(String... args) {
Population<TSPChromosome> tspPopulation = new Population<TSPChromosome>();
...
}
Implementation:
class Population<T extends Chromosome> {
private List<T> chromosomes = new ArrayList<T>();
public void addChromosomes(List<T> chromosomes) {
this.chromosomes.addAll(chromosomes);
}
public List<T> getChromosomes() {
return new ArrayList<T>(this.chromosomes);
}
}
It would be much safer if you made the Population generic itself:
public interface Population<T extends Chromosome> {
void addChromosomes(List<T> chromosomes);
List<T> getChromosomes();
}
public class TspPopulation implements Population<TspChromosome>{
@Override
public void addChromosomes(List<TspChromosome> chromosomes){
//
}
@Override
public List<TspChromosome> getChromosomes(){
//
}
}
That way you would not need any casting in client code.
I know GAs, and I would question whether your Population
implementation actually needs to know which kind of Chromosome
you put in. Do you really have different Population
implementations depending on the Chromosome
subclass? Or what you really want is to make sure you have the same subclass of Chromosome
in a Population
? In this last case, you can define the Population
interface as others suggested, and the make a generic implementation (or skip the interface altogether):
public class PopulationImpl implements Population<T extends Chromosome> {
private List<T> chromosomes;
@Override
public void addChromosomes(List<T> chromosomes) {
this.chromosomes.addAll(chromosomes);
}
@Override
public List<T> getChromosomes() {
return new ArrayList<T>(chromosomes);
}
}
Be careful not to put too many generics, or you will end up with generics hell, or tons of casts which will make generics more annoying than useful.
Yes, for instance:
public interface Population<T extends Chromosome>
{
void addChromosomes(List<T> chromosomes);
List<T> getChromosomes();
// More code here ...
}
public class TSPPopulation implements Population<TSPChromosome>
{
private List<TSPChromosome> chromosomes;
@Override
public void addChromosomes(List<TSPChromosome> chromosomes) {
this.chromosomes.addAll(chromosomes);
}
@Override
public List<TSPChromosome> getChromosomes() {
return new ArrayList<TSPChromosome>(chromosomes);
}
}
精彩评论