【问题标题】:Alternatives to "Extending" Java Enums“扩展”Java 枚举的替代方案
【发布时间】:2014-11-17 15:10:13
【问题描述】:

我正在做一个非常愚蠢的 ALife-esque 应用程序,并且我拥有以下具有以下继承关系的类:

(抽象)生命体

(抽象)生命体

植物和动物有一些共同的状态,理想情况下,我希望这种行为在 Lifeform 中以初级形式存在。

abstract class Lifeform
{
    public static enum State
    {
        IDLE,
        DEAD
    }

    protected void someMethodSomewhere()
    {
        ....
        state = State.IDLE;   // this to be recognized by inherited creatures
        ....
    }
    protected State state;
}

class Plant extends Lifeform
{
    public Plant() { state=new Plant.State(); }

    public static enum State extends Lifeform.State  // (can't)
    {
        FEEDING,
        REPRODUCING,
    }
}

class Animal extends Lifeform
{
    public Animal() { state=new Animal.State(); }

    public static enum State extends Lifeform.State  // (can't)
    {
        FEEDING,
        FORAGING,
        FLEEING,
        GROUPING,
        REPRODUCING
    }

    // elsewhere in some method
    public void someMethod()
    {
        switch(state)
        {
            case IDLE: (...)     // from Lifeform.State
            case FEEDING: (...)  // from Animal.State
            case DEAD: (...)
            ....
        }
    }
}

在后来的(1.5+)java 中是否有允许类似的功能,或者我最好将这个状态层次嵌入到它自己的传统类中?

【问题讨论】:

  • 您可以将所有状态放在一个 enum 中,并验证该类的确切状态。或者您可以单独使用enums。
  • @Luiggi,我早期拒绝的第一个解决方案,因为它涉及让基类维护有关所有潜在子类的信息。初级生命体不应该这样做。第二个使 Lifeform 类不会根据需要更改状态。
  • 嗯,在 Java 中你不能从 enum 扩展,所以你的用例是不可能的。有两种选择,可能你不应该使用enum 来解决这个问题
  • 如果你愿意,你可以让枚举实现接口,假设枚举需要有特定的方法。但是你正在做的不是一个选择。
  • @Luiggi,是的,这是我开始的最初前提——枚举本身无法解决这个问题。我不清楚在这里采取的最干净的路线。国家需要生活在各个层面。我希望保持生物的等级(而不是一种可以简单地自行进化成任何东西并仍然保持自己的等级的生命形式),并且我不希望任何特定的级别能够深入了解子级别,坦率地说,这将是粗俗的。

标签: java inheritance enums


【解决方案1】:

我不认为这是一个枚举问题,而是一个状态机问题。

您的名字State 在我看来意味着您实际上是在使用状态机。我不会为此使用enum,而是实际为适当的状态机建模。

从您在问题中发布的 states 来看,它们也暗示了一个有限状态机。我认为您将围绕这些enums 实施某种状态机作为最终结果,并且应该继续并从您最终要结束的地方开始。

我过去曾使用state machine compiler 取得了很好的效果,可以简单地创建和管理状态转换。

Ragel 看起来也是一个不错的解决方案。

你可以做你想做的唯一方法是推出你自己的 pre-1.4 TypeSafe Enum

在 Java 将 enum 作为类型之前,我在我的 IDE 中使用了 Type Safe Enum Pattern 模板来创建实际上更丰富的语言实现。

它本质上只是一个具有final 实例成员和private 构造函数和public final static 自身实例的Java 类。

我仍然会警告说,不允许扩展 enum 是有充分理由的,尝试解决它可能会给你带来比它解决的更多的痛苦。

【讨论】:

  • 很可能。然而,对我来说,练习是手动构建这样的状态机,这只是一个例子。我已经建立了自己的 SM,它的功能与我期望的一样。但是,我正在尝试在通过基因组继承的各个级别内构建功能,这涉及让超类管理它们自己理解的状态。考虑一下我没有(故意)提出问题的以下安排:(抽象)生命体
  • 是的,事实上,这与我自 1997 年以来一直在使用的解决方案相同。但从你的警告看来,如果我打算在继承的中使用任何枚举,那么我将朝着错误的方向前进时尚。不确定是否有一个干净的解决方案,因为我确实希望抽象超类(我想是“超级生物”)能够识别和修改状态,只要通过一组默认的受保护方法,这些方法可能会或可能不会在以后被覆盖。
  • 顺便说一句,你有没有碰巧看到这个怪物:javax.print.attribute.EnumSyntax?
【解决方案2】:

这是我多年来一直使用的解决方案,以防它对某人有所帮助。我已经重写了一些。

注意:它故意不实现值支持。这不是一个困难的改变,坦率地说,我不使用它们,所以我把它拔了出来。我还从我原来的古老版本重写了它。

注意:我主要在这里提供它,因为它包含 toString() 支持以从任何子类中产生字段名称(无论您使用什么)。

我还将由于访问限制导致的字段错误指定为灾难性(执行结束)错误。您可以将其修改为您选择的任何异常处理,但我建议您保持原样。

package tgm.utils;

import java.lang.reflect.Field;


public abstract class InheritableEnum
{
    protected InheritableEnum() {}

    public String toString()
    {
        String returnStr = "Unknown InheritableEnum["+super.toString()+"]";

        Field[] fields = this.getClass().getFields();        
        for (Field f : fields)
        {
            try
            {
                if (f.get(this) == this)
                {
                    returnStr = f.getName();
                    break;
                }
            }
            catch(IllegalAccessException e)
            {
                System.err.println("Illegal access on field["+f+"]");
                e.printStackTrace();
                System.exit(-1);
            }
        }

        return returnStr;
    }
}

然后你会类似地使用它:

public class State extends InheritableEnum
{
    public static final State DEAD    = new State();
    public static final State EATING  = new State();
    public static final State GROWING = new State();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-28
    • 2010-12-10
    相关资源
    最近更新 更多