我想为我在Web应用程序中提供的各种ajax服务定义一些枚举,例如:
Enum Service
{
REGISTER,
LOGIN,
NEWS,
FAQ
}
但是,这些枚举中的每一个都会有一个像Failed,Loaded等一样的状态。所以我希望能够使用REGISTER.LOADED
,LOGIN.LOADED
等来启动我的活动事件总线。但是每个状态枚举必须是唯一的。 I.e Register.LOADED
必须与FAQ.LOADED
不同,依此类推。
编辑:此外,我必须能够将所有状态存储在同一个散列映射中,例如Register.LOADED
和Login.LOADED
必须可以存储在同一个散列映射中。父服务枚举,即LOGIN, REGISTER
等,也必须存储在同一个散列映射中。
实现这一目标的最佳方法是什么?
答案 0 :(得分:7)
在OP的一些评论之后,我已经更新了我的代码。使用语法变得丑陋,在switch
块中可能无法正常工作,但我相信这可以实现OP的目标:
import java.util.*;
public class HelloWorld
{
public static void main(String []args)
{
// Different services are not equal
System.out.println(Service.REGISTER + "==" + Service.LOGIN + " :: " + Service.REGISTER.equals(Service.LOGIN));
// Same service is equal
System.out.println(Service.REGISTER + "==" + Service.REGISTER + " :: " + Service.REGISTER.equals(Service.REGISTER));
// Even after changing the state
Service tmp = Service.REGISTER;
Service.REGISTER.setState(Service.ServiceState.State.FAILED);
System.out.println(Service.REGISTER + "==" + tmp + " :: " + Service.REGISTER.equals(tmp));
Service.REGISTER.setState(Service.ServiceState.State.LOADED);
// Different service, same state is not equal
System.out.println(Service.REGISTER + "." + Service.REGISTER.state + "==" + Service.LOGIN + "." + Service.LOGIN.state + " :: " + Service.REGISTER.state.equals(Service.LOGIN.state));
// Same service, same state is equal (even when changing state around)
Service.ServiceState.State temp = Service.REGISTER.getState();
Service.REGISTER.setState(Service.ServiceState.State.LOADED);
System.out.println(Service.REGISTER + "." + Service.REGISTER.state + "==" + tmp + "." + temp + " :: " + temp.equals(Service.REGISTER.getState()));
// Same service, different state is not equal
Service.REGISTER.setState(Service.ServiceState.State.FAILED);
System.out.println(Service.REGISTER + "." + Service.REGISTER.state + "==" + tmp + "." + temp + " :: " + temp.equals(Service.REGISTER.getState()));
// Both service and state can be used as map keys
Map<Service, String> map = new HashMap<Service, String>();
Map<Service.ServiceState.State, String> map2 = new HashMap<Service.ServiceState.State, String>();
}
}
enum Service
{
REGISTER(),
LOGIN(),
NEWS(),
FAQ();
public ServiceState state;
Service()
{
this.state = new ServiceState();
}
public void setState(ServiceState.State s)
{
state.state = s;
}
public ServiceState.State getState() { return state.state; }
public static class ServiceState
{
public enum State
{
LOADED,
FAILED
}
public State state = State.LOADED;
public ServiceState(){}
public String toString() { return state.toString(); }
public int hashCode()
{
return state.hashCode();
}
public boolean equals(Object obj)
{
return state.equals(obj);
}
}
}
输出:
REGISTER==LOGIN :: false
REGISTER==REGISTER :: true
REGISTER==REGISTER :: true
REGISTER.LOADED==LOGIN.LOADED :: false
REGISTER.LOADED==REGISTER.LOADED :: true
REGISTER.FAILED==REGISTER.LOADED :: false
使用您想要的语法不太可能,但Java枚举基本上只是另一个名称的类。 (事实上,一旦编译,它们是扩展java.lang.Enum<E extends Enum<E>>
)
public class HelloWorld
{
public static void main(String []args)
{
Service a = Service.REGISTER;
a.state = Service.ServiceState.LOADED;
System.out.println(a);
}
}
enum Service
{
REGISTER(),
LOGIN(),
NEWS(),
FAQ();
public ServiceState state;
Service()
{
this.state = ServiceState.LOADED;
}
public String toString()
{
return super.toString() + "." + state.toString();
}
public enum ServiceState
{
LOADED,
FAILED
}
}
输出:
REGISTER.LOADED
答案 1 :(得分:2)
另一种选择是创建几个枚举。一个列出了服务:
enum Service {
REGISTER, LOGIN, NEWS, FAQ;
}
下一个列出所有州:
enum State { LOADED, FAILED }
现在你可以拥有一个在构造函数中获取服务和状态的类,它会覆盖equals()和hashCode()来区分它们:
new ServiceState(REGISTER, LOADED)
或者您创建另一个列出有效组合的枚举:
enum ServiceState {
REGISTER_LOADED(REGISTER, LOADED), ...
}
但是这个枚举非常大,输入的数量很快会变得非常大(如果你向其他枚举添加一个值,你需要将N个枚举添加到ServiceState
)
答案 2 :(得分:1)
一种解决方案是
enum Service {
REGISTER, LOGIN, NEWS, FAQ;
public final class State {
final ServiceState state;
private State(ServiceState st) {
state=st;
}
@Override
public String toString() {
return Service.this+"."+state;
}
}
final EnumMap<ServiceState, State> map=new EnumMap<>(ServiceState.class);
Service() {
for(ServiceState s:ServiceState.values()) map.put(s,new State(s));
}
public State state(ServiceState s) { return map.get(s); }
}
enum ServiceState { LOADED, FAILED }
这具有自动适应可能ServiceState
的更改的吸引力,但使用它们的代码有点奇怪:
Service.State ss=Service.LOGIN.state(ServiceState.LOADED); // LOGIN.LOADED
另一种选择是:
enum Service {
REGISTER, LOGIN, NEWS, FAQ;
public final class State {
final ServiceState state;
private State(ServiceState st) {
state=st;
}
@Override
public String toString() {
return Service.this+"."+state;
}
}
public final State LOADED=new State(ServiceState.LOADED);
public final State FAILED=new State(ServiceState.FAILED);
}
enum ServiceState { LOADED, FAILED }
这需要在您更改可能的ServiceState
时手动更新字段,但在使用它时它具有更吸引人的语法:
Service.State ss=Service.LOGIN.LOADED;
您还可以将ServiceState
enum
String
"LOADED"
,"FAILED"
等替换为enum
Service
,这样您就不需要保留{ {1}}和Service.State
内的字段同步。
请注意,这两个解决方案都依赖于private
的构造函数为enum
的事实,因此只存在equals
中存在的规范实例。因此,您无需覆盖hashCode
或Serializable
。如果你决定创建类readResolve
,你还应该添加一个{{1}}方法,该方法返回反序列化实例的规范表示。
答案 3 :(得分:0)
只需将“外部”枚举变成一个类,然后用“内部”枚举填充它:
public class Service {
public enum REGISTER {
CANCELLED
}
// ...
public enum LOGIN {
LOADED
}
}
或将其作为public static
嵌套到处理程序类中(如果是这种情况。
答案 4 :(得分:0)
虽然有一些好的答案可能适用于其他情况,但我决定采用以下解决方案,因为它最适合我的情况:
public enum Service
{
LOGIN,
REGISTER,
NEWS;
private final long LOADED, FAILED;
private RequestType()
{
LOADED = strToAscii(this.name() + "_LOADED" );
FAILED = strToAscii(this.name() + "_FAILED" );
}
public static long strToAscii(String str)
{
StringBuilder sb = new StringBuilder();
for (char c: str.toCharArray() )
{
sb.append( (int) c );
}
return Long.parseLong( sb.toString() );
}
}
这对我来说效果很好,因为我现在可以像我原先想要的那样RequestType.LOGIN.LOADED == RequestType.REGISTER.LOADED
。如果有人有任何改进建议,请随时提出建议。