Andrew S
Andrew S

Reputation: 2987

Nested Tree Structure Like Enums in Java - A different take on the usual nested enums Q and As

I have a requirement to nest enums in Java. However, on looking arround on Stackoverflow and the greater web, I see there does not seem to be a general convention on what nested enums are. I've seen lots of different interpretations, but none that match my need.

So let me start by discussing my requirement:

I require enums to permit naming conventions and a simple tree type structure for event types in my Java application. For example

Event.Draw.Square;
Event.Draw.Circle;
Event.Draw.Triangle;
Event.Draw.Poly;
Event.Draw.Line;

Event.File.Load;
Event.File.Save;

Event.Screen.Zoom;
Event.Screen.Flip;

Event.Ui.New;
Event.Ui.Close;

How I would envisage this in code would be the following, but obviously its not right. Any pointers please on how to obtain this with enums?

private enum event
{
    Draw {Square, Circle, Triangle, Poly, Line},
    File {Save, Save_As, Load},
    Screen {Zoom, Flip, Rotate_CW, Rotate_CCW},
    Ui {New_Workspace, Close}   
}

Then I would like for a case statement or conditional structure to be able to act upon say Event.Screen, or Event.Screen.Zoom. See the following methods for example:

public void evenTriggered(Event event)
{
    switch (event)
    {
    case Event.Draw:
            drawEvent(event.Draw);
    case Event.UI:
            uiEvent(event.Ui);
    case Event.Screen:
            screenEvent(event.Screen);
    case Event.File
            fileEvent(event.File);
    default: ;//do nothing

    }//end switch
}//end eventTriggered


public void drawEvent(Event.Draw event)
{

    switch(event.draw)
    {
    case Event.Draw.Square:
            workspace.addSquare();
        break;
    case Event.Draw.Circle:
            workspace.addCircle();
         break;  
    case Event.Draw.Triange:
        workspace.addTriangle();
         break;
     default: ;//do nothing

    };//end switch

}//end drawEvent

Thanks for taking the time to read my post and I look forward to your suggestions.

Andrew.

Upvotes: 0

Views: 1379

Answers (5)

eclps
eclps

Reputation: 94

This could be accomplished using an interface for your enums.

public interface Event {
}

public enum Draw implements Event {
  SQUARE, CIRCLE, TRIANGLE, POLY, LINE;
}

public enum File implements Event {
  LOAD, SAVE;
}

public enum Screen implements Event {
  ZOOM, FLIP;
}

public enum Ui implements Event {
  NEW, CLOSE;
}

Now you could react to these enum events with the following conditional structure:

public void evenTriggered(Event event)
{
  if(event instanceof Draw) {
    drawEvent((Draw)event);
  }
  else if(event instanceof Ui) {
    uiEvent((Ui)event);
  }
  else if(event instanceof Screen) {
    screenEvent((Screen)event);
  }
  else if(event instanceof File) {
    fileEvent((File)event);
  }
  else {
    //do nothing
  }
}//end eventTriggered

public void drawEvent(Draw event)
{

  switch(event)
  {
    case SQUARE:
      workspace.addSquare();
      break;
    case CIRCLE:
      workspace.addCircle();
      break;  
    case TRIANGLE:
      workspace.addTriangle();
      break;
    default: ;//do nothing

  };//end switch

}//end drawEvent

Upvotes: 0

Ray Tayek
Ray Tayek

Reputation: 10003

you could do something like my answer to ID3 Java Enum Tree. you may need a parent pointer for the children.

Upvotes: 0

Andrew S
Andrew S

Reputation: 2987

Ok after the good advice received I do beleive I have a workable solution to my requirements and I want to share it with you.

The basic solution is to create an object with two fields which are both enums. One the category and one the event. I can then make public static constant instances of the object for each category, event pairing. By keeping the constructor private, instances cannot be made externally and thus in error limiting the options to only those defined as constant and public.

I can now hold any of these constant instantiation in a type of EventType. For me this event type will be held in an Event object which will be used together with a central event system that all UI elements will register with to receive application wide event notifications such as redraw().

public class EventType
{
    public enum EventCategory{Draw, File, Screen, UI};

    public enum Event {Load, Save, Circle, Square, Triangle, Poly, Line, Flip, Zoom, Close,NewWorkspace};

    public final EventType FILE_LOAD = new EventType(EventCategory.File, Event.Load);
    public final EventType FILE_SAVE = new EventType(EventCategory.File, Event.Load);
    public final EventType DRAW_CIRCLE = new EventType{EventCategory.Draw, Event.Circle};
    public final EventType DRAW_SQUARE = new EventType{EventCategory.Draw, Event.Square};
    public final EventType DRAW_TRIANGLE = new EventType{EventCategory.Draw, Event.Triangle};
    public final EventType DRAW_POLY = new EventType{EventCategory.Draw, Event.Poly};
    public final EventType DRAW_LINE = new EventType{EventCategory.Draw, Event.Line};
    public final EventType SCREEN_FLIP = new EventType{EventCategory.Screen, Event.Flip};
    public final EventType SCREEN_ZOOM = new EventType{EventCategory.Screen, Event.zoom};
    public final EventType UI_CLOSE = new EventType{EventCategory.UI, Event.Close};
    public final EventType UI_NEW_WORKSPACE =  new EventType{EventCategory.UI, Event.NewWorkspace};

    public Event event;
    public EventCategory category;

    private EventType(EventCategory cat,  Event evt)
    {
        event = evt;
        category = cat;
    }//end constructor

}//end class 

Upvotes: 0

biziclop
biziclop

Reputation: 49724

Nested enums only make sense if you also have an is a descendant of operation. This is what you suggest in the first code sample. There isn't such a thing in the built-in Java enum implementation, and I can't see how it would ever fit in there.

However you're free to implement your own enum-like classes, with a private constructor and public static final instances, like we did before enums were added to Java. There are a few caveats, like serialization, but it is doable.

You can also do this:

public enum Foo {

EVENT,
EVENT_DRAW,
EVENT_DRAW_CIRCLE;

public boolean isDescendantOrSelf( Foo other ) {
    return other.name().startsWith( this.name() );
}

}

It's not perfect, as you won't be able to use them in switch/case statements, but it does give your flat enum values a tree structure based on their names. (But don't use my implementation, it's not good enough, I just wanted to show the concept.)

Upvotes: 2

MarioDS
MarioDS

Reputation: 13063

Why would you need nested enums? What you're doing is quite anti-OOP in my opinion. You should have a base class Event, let the Draw, File, UI and Screen classes inherit it and then use your enums to finally state the type of the specific event if you must (for DrawEvent, FileEvent etc...). The other option is static ints, and yet another option is to even make the "most specific" event-type another class. You'd have the following:

public void drawEvent(DrawEvent event)
{

    switch(DrawEvent.type) // type is of datatype DrawEventType, an enum
    {
    case DrawEventType.Square:
            workspace.addSquare();
            break;
    case DrawEventType.Circle:
            workspace.addCircle();
            break;  
    } //etcetera
}

Or with static integers:

public void drawEvent(DrawEvent event)
{

    switch(DrawEvent.type) // type is one of the DrawEvent static integers
    {
    case DrawEvent.SQUARE:
            workspace.addSquare();
            break;
    case DrawEvent.CIRCLE:
            workspace.addCircle();
            break;  
    } //etcetera
}

Upvotes: 1

Related Questions