user2626222
user2626222

Reputation: 169

Java Enums for Hierarchical/Tree like Structure

I need to create a structure that need to represent the following (For Category and Sub-Category).Its just one level deep. I am thinking of doing it using Java Enums and not sure how to represent this hierarchical structure.

My java objects (business objects) that represent a device will have both category and sub-category properties and I want to use an Enum instead of using integer codes like 100, 1 etc.. Some devices will have only category but not the sub-category (like 300 in the following example).

100  Switch  
     1   Interior
     2   Exterior
200  Security Sensor     
     1   Door Sensor
     2   Leak Sensor
     3   Motion Sensor
300  Camera

Any help is appreciated.

Thanks

Upvotes: 5

Views: 10018

Answers (6)

AncientSwordRage
AncientSwordRage

Reputation: 7608

This java.dzone article showcases is a beautiful example of hierarchical enums:

public enum OsType {
    OS(null),
        Windows(OS),
            WindowsNT(Windows),
                WindowsNTWorkstation(WindowsNT),
                WindowsNTServer(WindowsNT),
            Windows2000(Windows),
                Windows2000Server(Windows2000),
                Windows2000Workstation(Windows2000),
            WindowsXp(Windows),
            WindowsVista(Windows),
            Windows7(Windows),
            Windows95(Windows),
            Windows98(Windows),
        Unix(OS) {
                @Override
                public boolean supportsXWindows() {
                    return true;
                }
            },
            Linux(Unix),
            AIX(Unix),
            HpUx(Unix),
            SunOs(Unix),
    ;
    private OsType parent = null;

    private OsType(OsType parent) {
        this.parent = parent;
    }
}

The article show cases lots of little tricks you can pull off with this set up.

Upvotes: 7

stanleyerror
stanleyerror

Reputation: 788

I think this answer would be an excellent solution for you. With a type hierarchy like this:

public enum Component {
    Interior(Part.Switch),
    Exterior(Part.Switch),
    DoorSensor(Part.SecuritySensor),
    LeakSensor(Part.SecuritySensor),
    MotionSensor(Part.SecuritySensor),
    Camera(Part.Camera);

    private final Part kindOf;

    Component(Part kindOf) {
        this.kindOf = kindOf;
    }

    enum Part {
        Switch, SecuritySensor, Camera
    }

}

More detail can be found in Chapter Enum from Effective Java 2nd Edition.

Upvotes: 3

Thomas
Thomas

Reputation: 17412

Perhaps reconsider and do use integers here. However, instead of basing them on a decimal system (100, 200, 300,... for first level; 1, 2, 3,... for second level) base them on a binary representation.

// top-level
public static final int SWITCH          = 1 << 16;
public static final int SECURITY_SENSOR = 2 << 16;
public static final int CAMERA          = 4 << 16;

// sub-types of 'switch'
public static final int INTERIOR = SWITCH | 1;
public static final int EXTERIOR = SWITCH | 2;

// sub-types of 'security sensor'
public static final int DOOR_SENSOR   = SECURITY_SENSOR | 1;
public static final int LEAK_SENSOR   = SECURITY_SENSOR | 2;
public static final int MOTION_SENSOR = SECURITY_SENSOR | 4;

This allows you to do a weak form of inheritance testing:

if (value == SWITCH) {
   // value is a switch, but not interior or exterior
} else if (value & SWITCH != 0) {
   // value is interior or exterior
}

Upvotes: 0

Makoto
Makoto

Reputation: 106390

It seems unusual that you want to express this with an enumeration as opposed to inheritance. The thing with enumerations is that they're essentially compile-time constants, and if you wanted to generate more information in your hierarchy, you'd have to add more enumerations.

That can get messy, fast. It's also slightly contradictory to the real purpose of enumerations - as predefined constants instead of hierarchical entities.

What I propose is using an abstract class called CategoryBase in which to draw everything out of. Then, create your inheritance tree based off of that.

Here's a diagram:

Hierarchy diagram, showing CategoryBase on top, with children Camera, SubCategory, SecuritySensor, and Switch.

The bulk of the work is really holding properties, and we don't ever expect those properties to be changed once created, so we can allow our abstract class to hold them. We've also set them as final, so they can't be modified, either.

public abstract class CategoryBase {

    protected final int ranking;
    protected final String name;
    protected final SubCategory[] subCategories;

    protected CategoryBase(int ranking, String name, SubCategory... subCategories) {
        this.ranking = ranking;
        this.name = name;
        this.subCategories = subCategories;
    }

    public int getRanking() {
        return ranking;
    }

    public String getName() {
        return name;
    }

    public SubCategory[] getSubCategories() {
        return subCategories;
    }
}

From there, we can start basing our marker classes off of this - including SubCategory, since it's really just a holder of information that's represented in a different way.

This would also make writing the marker classes straightforward and simple. For example, here's Camera:

public class Camera extends CategoryBase {

    protected Camera(int ranking, String name) {
        super(ranking, name);
    }
}

It's got a striking similarity to SubCategory - a SubCategory doesn't have any nested SubCategorys, so we don't pass in anything to the vararg portion of the constructor.

For something that does have SubCategorys, we need to instantiate them on construction. Here's SecuritySensor as an example.

public class SecuritySensor extends CategoryBase {

    public SecuritySensor(int ranking, String name) {
        super(ranking, name,
                new SubCategory(1, "Door Sensor"),
                new SubCategory(2, "Leak Sensor"),
                new SubCategory(3, "Motion Sensor"));
    }
}

This approach gives you some flexibility around ranking as well - if you wanted to be able to specify the exact ranking of the subcategories at runtime, you'd replace this constructor with one that supported the vararg signature.

Upvotes: 1

Ray Tayek
Ray Tayek

Reputation: 10003

you can do something like the code below. but that is probably not quite what you want. you could add the child enums to the constructor for the parent enum like here.

enum Stuff {
    Swich,Sensor,Camera;
    enum swich {
        interior,exterior;
        enum Where {
            bathroom,kitchen
        }
    }
    enum sensor {
        door,leak,motion
    }
}

Upvotes: 0

andy
andy

Reputation: 1356

Does following code meet your request?

public enum Category {Switch, ...}
public enum SubCategory {Interior, ...}

Upvotes: -1

Related Questions