如何启用枚举继承

时间:2016-02-26 11:02:50

标签: java inheritance enums

我正在编写一个库,它有一组预定义的枚举值。 比方说,我的枚举如下所示。

public enum EnumClass {
    FIRST("first"),
    SECOND("second"),
    THIRD("third");

    private String httpMethodType;

}

现在使用此库的客户端可能需要添加更多值。假设客户需要添加CUSTOM_FIRSTCUSTOM_SECOND。这不会覆盖任何现有值,但会使枚举具有5个值。

在此之后,我应该能够使用类似<? extends EnumClass>的东西来获得5种不变的可能性。

实现这一目标的最佳方法是什么?

4 个答案:

答案 0 :(得分:40)

您不能enum扩展另一个enum,也不能通过继承“添加”现有enum的值。

但是,enum可以实现interface

我要做的是让原始enum实现标记interface(即没有方法声明),然后您的客户可以创建自己的enum来实现相同的interface }。

然后,您的enum值会被他们的共同interface引用。

为了加强要求,您可以让您的界面声明相关的方法,例如在你的情况下,public String getHTTPMethodType();

的行

这会强制实现enum来为该方法提供实现。

此设置与充足的API文档相结合,有助于以相对受控的方式添加功能。

自包含示例(不介意这里的懒名称)

package test;

import java.util.ArrayList;
import java.util.List;

public class Main {

    public static void main(String[] args) {
        List<HTTPMethodConvertible> blah = new ArrayList<>();
        blah.add(LibraryEnum.FIRST);
        blah.add(ClientEnum.BLABLABLA);
        for (HTTPMethodConvertible element: blah) {
            System.out.println(element.getHTTPMethodType());
        }
    }

    static interface HTTPMethodConvertible {
        public String getHTTPMethodType();
    }
    static enum LibraryEnum implements HTTPMethodConvertible {
        FIRST("first"),
        SECOND("second"),
        THIRD("third");
        String httpMethodType;
        LibraryEnum(String s) {
            httpMethodType = s;
        }
        public String getHTTPMethodType() {
            return httpMethodType;
        }
    }
    static enum ClientEnum implements HTTPMethodConvertible {
        FOO("GET"),BAR("PUT"),BLAH("OPTIONS"),MEH("DELETE"),BLABLABLA("POST");
        String httpMethodType;
        ClientEnum(String s){
            httpMethodType = s;
        }
        public String getHTTPMethodType() {
            return httpMethodType;
        }
    }
}

<强>输出

first
POST

答案 1 :(得分:7)

枚举不可扩展。简单地解决您的问题

  • 在类中转换枚举
  • 为预定义类型创建常量
  • 如果您想要替换Enum.valueOf:在静态地图中跟踪该类的所有实例

例如:

public class MyType {
    private static final HashMap<String,MyType> map = new HashMap<>();
    private String name;
    private String httpMethodType;

    // replacement for Enum.valueOf
    public static MyType valueOf(String name) {
         return map.get(name);
    }

    public MyType(String  name, String httpMethodType) {
         this.name = name;
         this.httpMethodType = httpMethodType;
         map.put(name, this);
    }

    // accessors
    public String name() { return name; }
    public String httpMethodType() { return httpMethodType; }

    // predefined constants
    public static final MyType FIRST = new MyType("FIRST", "first");
    public static final MyType SECOND = new MyType("SECOND", "second");
    ...
}

答案 2 :(得分:1)

将Enum当作具有静态最终实例的最终类来考虑。当然,您不能扩展最终类,但可以在库中将非最终类与静态最终实例一起使用。您可以在JDK中看到这种定义的示例。可以使用包含其他日志记录级别集的类来扩展java.util.logging.Level类。

如果您接受这种实现方式,则您的库代码示例可能类似于:

public class EnumClass {
    public static final FIRST = new EnumClass("first");
    public static final SECOND = new EnumClass("second");
    public static final THIRD = new EnumClass("third");

    private String httpMethodType;

    protected EnumClass(String name){
        this.httpMethodType = name;
    }
}

客户端应用程序可以通过继承扩展静态成员列表:

public final class ClientEnum extends EnumClass{
    public static final CUSTOM_FIRST = new ClientEnum("custom_first");
    public static final CUSTOM_SECOND = new ClientEnum("custom_second");

    private ClientEnum(String name){
        super(name);    
    }
}

我认为该解决方案与您的要求很接近,因为所有静态实例都可以从客户端类中看到,并且它们都将满足您的通用通配符。

答案 3 :(得分:0)

我们通过这种方式修复了枚举继承问题,希望有所帮助

我们的应用程序有几个类,每个类都有很少的子视图(嵌套视图),为了能够在childViews之间导航并保存currentChildview,我们将它们保存为每个类中的枚举。 但我们不得不在每个枚举中复制粘贴,一些常见的功能,如next,previous等。 为了避免我们需要BaseEnum,我们使用interface作为基本枚举:

public interface IBaseEnum {
    IBaseEnum[] getList();
    int getIndex();

    class Utils{
        public IBaseEnum next(IBaseEnum enumItem, boolean isCycling){
            int index = enumItem.getIndex();
            IBaseEnum[] list = enumItem.getList();
            if (index + 1 < list.length) {
                return list[index + 1];
            } else if(isCycling)
                return list[0];
            else
                return null;
        }

        public IBaseEnum previous(IBaseEnum enumItem, boolean isCycling) {
            int index = enumItem.getIndex();
            IBaseEnum[] list = enumItem.getList();

            IBaseEnum previous;
            if (index - 1 >= 0) {
                previous = list[index - 1];
            }
            else {
                if (isCycling)
                    previous = list[list.length - 1];
                else
                    previous = null;
            }
            return previous;
        }
    }
}

这就是我们使用它的方式

enum ColorEnum implements IBaseEnum {
    RED,
    YELLOW,
    BLUE;
    @Override
    public IBaseEnum[] getList() {
        return values();
    }

    @Override
    public int getIndex() {
        return ordinal();
    }

    public ColorEnum getNext(){
    return (ColorEnum) new Utils().next(this,false);
    }

    public ColorEnum getPrevious(){
        return (ColorEnum) new Utils().previous(this,false);
    }
}

你也可以在界面上添加getNext / getPrevious