Enum Base Classes in Java

13,000

Solution 1

You will have to implement this yourself, you cannot extend already implemented behaviour. You can however force yourself, or anyone else, to implement various methods:

public interface Item {
    public int getId();
    public String getName();
}

public enum Tool implements Item {
    Pickaxe("Pickaxe", 101),
    Saw("Saw", 201);

    private final int id;
    private final String name;

    public Item(final String name, final int id) {
        this.id = id;
        this.name = name;
    }

    @Override
    public int getId() {
        return id;
    }

    @Override
    public String getName() {
        return name;
    }
}

That is part one, now you do not want to access getIds() and getNames() via an enum 'instance' itself, but you want to access them via the class as a static function.

I hope this helps you enough already, but it is far from complete and with generics there might even be ways to do it more simpler, but do understand that enums cannot extend anything.

Solution 2

You can go part-way.

public class MyItem extends Item<MyItem.Items> {
  public MyItem () {
    // Tell my parent class about my enum.
    super(EnumSet.allOf(Items.class));
  }
  public enum Items implements Item.Items {
    Pickaxe("Pickaxe", 101),
    Saw("Saw", 201);
    private final int id;
    private final String name;

    // You have to do these.
    Items(String name, int id) {
      this.id = id;
      this.name = name;
    }

    @Override
    public int getId() {
      return this.id;
    }

    @Override
    public String getName() {
      return this.name;
    }

  }
}

// The parent class that does the common work.
public class Item<I extends Enum<I> & Item.Items> {
  // Keep track of the items.
  private final Set<I> items;

  // Pas a set of the items in the constructor.
  public Item(Set<I> items) {
    this.items = items;
  }

  // The interface.
  public interface Items {
    public int getId();

    public String getName();

  }

  // Ready-made functionality.
  public List<Integer> getIds() {
    List<Integer> ids = new ArrayList<>();
    for (I i : items) {
      ids.add(i.getId());
    }
    return ids;
  }

  public List<String> getNames() {
    List<String> names = new ArrayList<>();
    for (I i : items) {
      names.add(i.getName());
    }
    return names;
  }

}

Here you still have to have your enum constructor store the fields but you only need to implement an interface. The parent class can then do all of the work on a Set it is given at construct time.

You can certainly use this technique to move a lot of the code out int a parent class but sadly not all.

Share:
13,000
B-Fir3
Author by

B-Fir3

Updated on June 04, 2022

Comments

  • B-Fir3
    B-Fir3 almost 2 years

    What is the best way to use this as a base class for an Enum like class. I would like to be able to create different concrete types without having to re-code the getter methods.

    public enum Tool extends Item
    {
        Pickaxe("Pickaxe", 101),
        Saw("Saw", 201);
    }
    

    And Tool.getNames() would return a list of all the Item names in the Tool class.

    public enum Item
    {
        Default("Name", 0);
    
        private final int id;
        private final String name;
    
        Item(String name, int id)
        {
            this.id = id;
            this.name = name;
        }
    
        public int getId()
        {
            return this.id;
        }
    
        public int[] getIds()
        {
            Item[] items = Item.values();
            int[] ids = new int[items.length];
            for (int i = 0; i < items.length; i++)
            {
                ids[i] = items[i].getId();
            }
            return ids;
        }
    
        public String getName()
        {
            return this.name;
        }
    
        public String[] getNames()
        {
            Item[] items = Item.values();
            String[] names = new String[items.length];
            for (int i = 0; i < items.length; i++)
            {
                names[i] = items[i].getName();
            }
            return names;
        }
    }
    

    I know it isn't possible like this, but how could I approach this situation? I'd like to be able to access the members of each class just like you would an enum: Tool.Pickaxe.