3

I am trying to establish an abstract class. I want to ensure that any subclass has an enum listing its potential actions.

For instance, Foo is an abstract class.

Fee extends Foo and can...
    TALK
    WALK
    SLEEP

Bar extends Foo and can...
    SIT
    STARE

I want to give the parent class the field and have the child classes fill in the enum with the actions that it is capable of. How would I approach this?

If I define an enum in a class, for instance, give it some generic actions, will it be passed to a subclass and could a subclass extend the enum? That could be another option.

Carl Manaster
  • 39,912
  • 17
  • 102
  • 155
gobernador
  • 5,659
  • 3
  • 32
  • 51

2 Answers2

4

I don't know that I agree with the approach but you could do

enum CanDos {
  TALK,
  WALK,
  SLEEP,
  SIT,
  STARE
}

And then the class could have

abstract class Foo {
  abstract Set<CanDos> getCanDos();
  //or
  abstract boolean can(CanDos item);
}

And you can use an EnumSet for efficient storage of the capabilities.

If all you are looking for is the Right Thing to provide a set of enums (like the field in the parent abstract class you mention) then I think EnumSet<CanDos> is your guy. In that case

abstract class Foo {

  private final Set<CanDos> candos;

  protected Foo(Set<CanDos> candos) 
  {
     this.candos = new EnumSet<CanDos>(candos);
  }

  public boolean can(CanDos item) {
    return candos.contains(item);
  }
}

Alternatively you could avoid the abstract class altogether (or at least not mandate it see e.g. this question or this one). The well-regarded book Effective Java suggests "Prefer interfaces to abstract classes".

To do this, instead

enum CanDos {
  TALK,
  WALK,
  SLEEP,
  SIT,
  STARE
}

public interface FooThatCanDo {
  boolean can(CanDos item);
}

If you really think there's value in a common inheritance root (which you should think hard about) then you could provide an abstract base implementation as shown above, and declare that it implements FooThatCanDo.

Community
  • 1
  • 1
andersoj
  • 22,406
  • 7
  • 62
  • 73
  • I do think that I want an abstract class because I have a standard way to do each of these things (that is, a final method `doStuff(CanDo doThis)`). Does this sound like a good idea? – gobernador May 09 '12 at 23:44
  • @gobernador: I'd go take a look at the guidance first. There are good reasons to use abstract classes, but more good reasons to avoid where possible. I suggest reading the Effective Java section on the topic http://my.safaribooksonline.com/book/programming/java/9780137150021/classes-and-interfaces/ch04lev1sec6 or at the very least this question: http://stackoverflow.com/questions/56867/interface-vs-base-class, and ask whether the criteria apply to you. – andersoj May 09 '12 at 23:46
  • @gobernador: You can also have the best of both worlds -- write an abstract class, and include it/subclass it by composition as a field in your subclasses rather than inheriting from it. This can be a good middle ground that lets you have the common code while not cementing inconvenient inheritance trees. If you write more about your specific problem above, might be able to offer more. – andersoj May 09 '12 at 23:48
  • @gobernador: To clarify -- it's not abstract classes that are to be avoided; rather it's solving every problem via inheritance (a hammer that gets applied to too many non-nails). It is usually better to describe the abstraction through an interface (more flexible; allows multiple inheritance) and offer abstract classes where appropriate. – andersoj May 09 '12 at 23:51
  • Your comments have been very helpful. Thank you. I ended up building an abstract class with some assisting interfaces. – gobernador May 10 '12 at 22:50
0

I don't think an enum is what you are looking for, at least not directly. Perhaps you could use a BitSet.

class Base {
    private static EnumSet actions;

    public EnumSet getActions() { return actions; }
}

class Derived extends Base {
    private static EnumSet actions;

    @Override
    public EnumSet getActions() { 
        return new EnumSet(actions).addAll(super.getActions()); 
    }
}
Mike
  • 654
  • 2
  • 7
  • 22