用于分层/树状结构的Java枚举

时间:2014-04-17 01:55:15

标签: java enums

我需要创建一个需要表示以下内容的结构(对于类别和子类别)。它只有一层深度。我正在考虑使用Java Enums进行操作,并且不确定如何表示这种层次结构。

我代表设备的java对象(业务对象)将同时具有类别和子类别属性,我想使用Enum而不是使用整数代码,如100,1等。有些设备只有类别但不是子类别(如下例中的300)。

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

感谢任何帮助。

由于

6 个答案:

答案 0 :(得分:3)

java.dzone文章展示是分层枚举的一个很好的例子:

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;
    }
}

这篇文章展示了一些可以通过此设置实现的小技巧。

答案 1 :(得分:2)

我认为this answer对您来说是一个很好的解决方案。使用类似这样的类型层次结构:

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
    }

}

更多细节可以在 Effective Java 2nd Edition 的章节枚举中找到。

答案 2 :(得分:1)

你想用枚举而不是继承来表达这一点似乎很不寻常。枚举的内容是它们本质上是编译时常量,如果您想在层次结构中生成更多信息,则必须添加更多枚举。

那可能会变得凌乱,快速。它也与枚举的真正目的略有矛盾 - 作为预定义常量而不是分层实体。

我建议使用一个名为CategoryBase的抽象类来绘制所有内容。然后,根据它创建继承树。

这是一张图表:

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

大部分工作都是持有属性,我们不希望这些属性在创建后被更改,因此我们可以允许我们的抽象类来保存它们。我们还将其设置为final,因此无法对其进行修改。

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;
    }
}

从那里开始,我们可以开始基于此标记类 - 包括SubCategory,因为它实际上只是以不同方式表示的信息的持有者。

这也使编写标记类变得简单明了。例如,这里是Camera

public class Camera extends CategoryBase {

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

它与SubCategory有惊人的相似之处 - SubCategory没有任何嵌套SubCategory,所以我们不会传递任何内容到构造函数的vararg部分。

对于 具有SubCategory的内容,我们需要在构造时实例化它们。这里以SecuritySensor为例。

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"));
    }
}

这种方法为您提供了一些围绕排名的灵活性 - 如果您希望能够在运行时指定子类别的确切排名,您可以将此构造函数替换为支持的构造函数vararg签名。

答案 3 :(得分:0)

您可以执行以下代码之类的操作。但这可能不是你想要的。您可以将子枚举添加到父{1}}之类的父枚举的构造函数中。

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

答案 4 :(得分:0)

也许重新考虑并在这里使用整数。但是,不是将它们基于十进制系统(100,200,300,......用于第一级; 1,2,3,......用于第二级),而是基于二进制表示。

// 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;

这允许您进行弱形式的继承测试:

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

答案 5 :(得分:-1)

以下代码是否符合您的要求?

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