扩展枚举字段Java

时间:2013-10-30 14:49:16

标签: java oop enums

我知道在Java中扩展枚举是不可能的,但我想为下面找到一个优雅的解决方案

我正在尝试对包含跨地区的各种Web服务的http端点的枚举(或类)进行建模,比如我有服务A和B,每个将在美国,欧盟,日本或中国有4个地区特定的终点。 (这基本上是我正在编写的一些单独的调试代码,在生产中将从配置中选择端点)

我希望做这样的事情(不符合java代码)。

public enum IEndPoint {
    NA_END_POINT,
    EU_END_POINT,
    JP_END_POINT,
    CN_END_POINT,
}

public enum ServiceAEndPoint extends IEndPoint {
   NA_END_POINT("http://A.com/");
   EU_END_POINT("http://A-eu.com/");
   JP_END_POINT("http://A-jp.com/");
   CN_END_POINT("http://A-cn.com/");
}

我可以使用接口来实现这一点,我为每个区域都有一个方法,但在我看来,枚举方式更具表现力,有没有更好的方法来模拟这个?我正在寻找的是,如果有更好的方法来模拟继承关系,并具有枚举的表达能力。

ServiceAEndPoint.NA_END_POINT

VS

serviceAEndPoint.getNAEndPoint()

6 个答案:

答案 0 :(得分:3)

我假设您还需要一个ServiceBEndPoint枚举(和类似的)。在这种情况下,我不认为你的模型真的有那么大意义。

IEndPoint实际上是服务可能正在运行的环境/区域的枚举。它不是服务本身的枚举。每个服务(A,B或其他)将为每个区域提供不同的地址。

因此我会坚持使用IEndPoint enum,然后在某些特定于服务的代码中有一个查找映射,它将为您提供给定端点的地址。像这样:

public enum IEndPoint {
    NA_END_POINT,
    EU_END_POINT,
    JP_END_POINT,
    CN_END_POINT,
}

public class ServiceABroker {
   private static final Map<IEndPoint, String> addressesByEndPoint;
   static {
      addressesByEndPoint = new EnumMap<>();
      addressesByEndPoint.put(NA_END_POINT, "http://A.com/");
      addressesByEndPoint.put(EU_END_POINT, "http://A-eu.com/");
      addressesByEndPoint.put(JP_END_POINT, "http://A-jp.com/");
      addressesByEndPoint.put(CN_END_POINT, "http://A-cn.com/");
   }

   public String getAddressForEndPoint(IEndPoint ep) {
       return addressesByEndPoint.get(ep);
   }
}

答案 1 :(得分:1)

如果这些是静态最终常量,那么只需将它们放在界面中即可。将接口命名为IServiceAEndPointKeys,其中部分是约定。

这里我认为 enum 更适合和有用:

  • 示例1:文件类型。包含 jpg pdf 等的枚举
  • 示例2:列定义。如果我有一个包含3列的表,我会写一个枚举声明 ID Name Description (例如),每个都有参数例如列标题名称列宽列ID

答案 2 :(得分:1)

你可能想要考虑这样的事情:

public abstract class EndpointFactory {
    public abstract String getNAEndPoint();
    public abstract String getEUEndPoint();
}

public class ServiceAEndpointFactory extends EndpointFactory {
    public static final String NA_END_POINT = "http://A.com/";
    public static final String EU_END_POINT = "http://A-eu.com/";

    public String getNAEndPoint() {
       return ServiceAEndpointFactory.NA_END_POINT;
    }

    public String getEUEndPoint() {
       return ServiceAEndpointFactory.EU_END_POINT;
    }
}

public class ServiceBEndpointFactory extends EndpointFactory {
    public static final String NA_END_POINT = "http://B.com/";
    public static final String EU_END_POINT = "http://B-eu.com/";

    public String getNAEndPoint() {
       return ServiceAEndpointFactory.NA_END_POINT;
    }

    public String getEUEndPoint() {
       return ServiceAEndpointFactory.EU_END_POINT;
    }
}

然后你可以像这样直接引用你的字符串:

ServiceAEndpointFactory.NA_END_POINT;

或者,如果在执行之前不知道服务类型,则可以使用基础对象:

EndpointFactory ef1 = new ServiceAEndpointFactory();
String ep = ef1.getNAEndPoint();

这样做的缺点是重新定义了每个子类中的get * Endpoint()函数。您可以通过将静态最终变量移动到基类中不是静态的并且仅将getter / setter放在基类中一次来消除这种情况。但是,缺点是你无法在没有实例化对象的情况下引用这些值(这实际上模仿了我认为对ENUM有用的东西)。

答案 3 :(得分:1)

我不确定我是否理解你的问题,但是您可以在枚举中添加方法,例如您可以执行以下操作:

public enum ServiceAEndPoint{
    NA_END_POINT("http://A.com/");
    EU_END_POINT("http://A-eu.com/");
    JP_END_POINT("http://A-jp.com/");
    CN_END_POINT("http://A-cn.com/");

    private final String url;

    private EndPoint(String url){
        this.url=url;
    }

    public String getURL(){
        return url;
    }
}

答案 4 :(得分:1)

枚举不能以这种方式扩展,主要是因为枚举不能被分类,或者他们必须遵守的限制是不可能强加的。

而是利用接口,如此

public interface IEndPoint;

public enum DefaultEndPoints implements IEndPoint {
    NA_END_POINT,
    EU_END_POINT,
    JP_END_POINT,
    CN_END_POINT,
}

public enum DefaultServiceEndPoints implements IEndPoint {
   NA_END_POINT("http://A.com/");
   EU_END_POINT("http://A-eu.com/");
   JP_END_POINT("http://A-jp.com/");
   CN_END_POINT("http://A-cn.com/");
}

public void doSomething(IEndPoint endpoint) {
  ...
}

一个人不能以你希望的方式进行子类化的原因与枚举的合同有关,这个合同将通过.equals(object)==相等。如果你可以继承,这有意义吗?

if ( (DefaultEndPoints)JP_END_POINT == (DefaultServiceEndPoints)JP_END_POINT) {

}

如果你说“是”那么我希望能够做到这一点

DefaultEndPoint someEndpoint = DefaultServiceEndPoints.JP_END_POINT;

会因错误而打开一扇门,因为无法保证一个枚举声明中的枚举条目在另一个枚举声明中。

可能有所不同吗?也许,但事实并非如此,改变它肯定会引入许多必须经过深思熟虑的复杂化(或者它会为Java强大的静态类型检查开辟道路)。

答案 5 :(得分:0)

这样的模式对你有什么吸引力?我让enum实现interface并在Debug集和Release集中实现接口。然后,发布集可以从enum名称派生属性名称 - 这很整洁。

public interface HasURL {
  public String getURL();
}

public enum DebugEndPoints implements HasURL {
  NA,
  EU,
  JP,
  CN;

  @Override
  public String getURL() {
    // Force debug to go to the same one always.
    return "http://Debug.com/";
  }
}

public enum NormalEndPoints implements HasURL {
  NA,
  EU,
  JP,
  CN;
  final String url;

  NormalEndPoints () {
    // Grab the configured property connected to my name.
    this.url = getProperty(this.name());
  }
  @Override
  public String getURL() {
    return url;
  }
}