Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating an EnumMap with a generic type Enum

Tags:

java

If I have a bunch of classes that all contain an Enum and EnumMap and I want to create a superclass for those classes.

public interface ColorEnum {
}

class ColorMarbles extends Toy {
    enum MARBLE implements ColorEnum
        { BLUE, GREEN }
    EnumMap<MARBLE, String> names = new EnumMap<MARBLE, String>(MARBLE.class);
    //stuff
    // fields

    public void populate(ArrayList<String> designer) {
        int i = 0;
        for(MARBLE marble : MARBLE.values()) {
            marble.name = designer.get(i);
            i++;
        }
    }
}

class ColorBalloons extends Toy {
    enum BALLOON implements ColorEnum
        { YELLOW, RED }
    EnumMap<BALLOON, String> names = new EnumMap<BALLOON, String>(BALLOON.class);
    //stuff
    // fields

    public void populate(ArrayList<String> designer) {
        int i = 0;
        for(BALLOON balloon : BALLOON.values()) {
            balloon.name = designer.get(i);
            i++;
        }
    }
}

How do I make create a superclass to have a generic EnumMap that contains an enum of type ColorEnum like this?

public abstract class Toy {
    EnumMap<ColorEnum, String> names;
}

eidt: I realize that I was too vague with my example. Dogs are probably a bad example. I change it to something hopefully more clear.

What I have is a bunch of classes with methods like populate which populates the EnumMap. The names are in a predefined order. Instead of defining populate in every class, I'm hoping to be able to bring it to the Toy superclass so I don't have to keep copy-pasting in each new class type Toy.

Hopefully this will explain more what I'm looking for.

like image 512
Aboutblank Avatar asked Feb 17 '23 11:02

Aboutblank


2 Answers

I have a feeling your design is needlessly overcomplicated.

With enums

If you don't require a class inheritance, you can work with enums directly as with top level classes.

public interface Animal {}

public enum Dog implements Animal {
    HUSKY("Husky"), LAB("Labrador");

    private final String name;

    Dog(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

Enums can declare fields, methods and implement interfaces like any other Java classes. Their only limitation is that their direct superclass is always java.lang.Enum and they can't be extended.

However every enum constant can have its own set of unique data passed to its constructor. It is even possible that each of the constants can override a common method of that enum with its unique implementation.

A nice tutorial explaining more about the full power of enums: http://javarevisited.blogspot.cz/2011/08/enum-in-java-example-tutorial.html


Without enums

In case you need an actual class inheritance for sharing some common methods (for example from the Animal superclass), I still would drop the map approach and rather try something more OOP oriented:

public class Animal {
}

public abstract class Dog extends Animal {

    public abstract String getName();

    public static class Husky extends Dog {
        @Override
        public String getName() {
            return "husky";
        }
    }

    public static class Lab extends Dog {
        @Override
        public String getName() {
            return "labrador";
        }
    }

}
like image 61
Natix Avatar answered Feb 28 '23 05:02

Natix


One mechanism I have used for something like this is to extend a generic base class that has a generic parameter that allows you to pass the Enum details up to it.

This example defines a base Table class for database tables:

public class Table<Column extends Enum<? extends Column>> {
  // Name of the table.
  protected final String tableName;
  // All of the columns in the table. This is actually an EnumSet so very efficient.
  protected final Set<Column> columns;

  /**
   * The base interface for all Column enums.
   */
  public interface Columns {
    // What type does it have in the database?
    public Type getType();
  }

  // Small list of database types.
  public enum Type {
    String, Number, Date;
  }

  public Table(String tableName,
               Set<Column> columns) {
    this.tableName = tableName;
    this.columns = columns;
  }

}

Now you can subclass this:

public class VersionTable extends Table<VersionTable.Column> {

  public enum Column implements Table.Columns {
    Version(Table.Type.String),
    ReleaseDate(Table.Type.Date);

    // Sadly all of this must be in ALL of your enums but most of the work can be pushed up to `Table`
    final Table.Type type;

    Column(Table.Type type) {
      this.type = type;
    }

    @Override
    public Type getType() {
      return type;
    }
  }

  public VersionTable() {
    super("Versions", EnumSet.allOf(Column.class));
  }
}

and make use of functionality in the parent class that handles your enum.

Note here I am passing an EnumSet to the Table constructor. I am sure you could change this to accommodate your EnumMap requirement if you decide an EnumSet is insufficient.

like image 22
OldCurmudgeon Avatar answered Feb 28 '23 05:02

OldCurmudgeon