5

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

user2626222
  • 169
  • 2
  • 13

6 Answers6

7

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.

AncientSwordRage
  • 7,086
  • 19
  • 90
  • 173
3

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.

Community
  • 1
  • 1
stanleyerror
  • 728
  • 1
  • 9
  • 23
1

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.

Makoto
  • 104,088
  • 27
  • 192
  • 230
0

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
    }
}
Community
  • 1
  • 1
Ray Tayek
  • 9,841
  • 8
  • 50
  • 90
0

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
}
Thomas
  • 17,016
  • 4
  • 46
  • 70
  • 1
    While this would do the job, I'd strongly discourage using bitwise arithmetics in *almost all situations*. To quote Effective Java, Item 32: "But bit fields have all the disadvantages of int enum constants and more. It is even harder to interpret a bit field than a simple int enum constant when it is printed as a number. Also, there is no easy way to iterate over all of the elements represented by a bit field." – mdo Apr 17 '14 at 06:28
  • It's certainly a good idea to carefully make design decisions. But just because something is written in a book doesn't mean you have to follow it blindly. It really depends on your use case - if you need a certain feature, such as, e.g., quick inheritance testing, which enums can't provide per se then it's up to you whether you want to work around it, say with multiple or nested enums, or use a different approach. – Thomas Apr 17 '14 at 07:46
  • 1
    I would not advise this because it's in the book, I cited the book because Bloch's statement is quite precise. In my opinion bitwise operations are similar to programming with pointers: there's a good deal of developers out there that don't grasp the concepts or at least have huge problems with these topics. Joel Spolsky wrote a [nice article](http://www.joelonsoftware.com/articles/fog0000000006.html) a couple of years ago. So if I would code this in a team, I would spare bitwise operations. The SCJP exam dropped bitwise ops thus communicating the connotation: "Don't use it!" – mdo Apr 17 '14 at 08:12
  • I appreciate your opinion but I don't share it. – Thomas Apr 17 '14 at 08:46
-1

Does following code meet your request?

public enum Category {Switch, ...}
public enum SubCategory {Interior, ...}
andy
  • 1,336
  • 9
  • 23
  • 1
    No. I want to maintain the relation between the category and sub-category. Having 2 separate enums will let you set Category=100 and Sub-category=3 (Switch - Motion Sensor) which is wrong. Thanks. – user2626222 Apr 17 '14 at 02:07
  • @user2626222 that shouldn't happen at all because `Motion Sensor` wouldn't exist in the values of `Switch`... – Obicere Apr 17 '14 at 02:09
  • then you can add another enum like {enum Category cate; enum SubCategory subCate; SwitchInterior(Switch, Interior), SwitchExterior(Switch, Exterior)...} then using this enum in your object class – andy Apr 17 '14 at 02:24