我知道在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()
答案 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 更适合和有用:
答案 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;
}
}