在Java中声明来自多个库的一组常量有哪些选项?
例如,我有一个网络消息协议。该协议有一些标准消息,并允许创建自定义消息。每条消息都有一个唯一的ID号。我很想在我的应用程序中将所有这些唯一id组合成一个枚举。类似…
public enum MessageType
{
//Standard messages in one library
FooMsg(1),
BarMsg(2),
//Custom messages in another library
MyCustomMessage(100),
MyOthercustomMessage(101);
private long msgNumber;
public long getMessageNumber(long msgNumber) { return msgNumber;}
public static MessageType fromMessageNumber(long messageNumber)
{
//Reverse lookup code here...
}
//Few more utilities that don't matter for this question
private MessageType(long msgNumber)
{
this.msgNumber = msgNumber;
}
}
然后我可以为消息类型创建泛型方法。
public void doStuff(MessageType msgType, MyMessageObject data)
{
switch(msgType)
{
case FooMsg: //Do stuff
break;
//Other stuff
}
}
然而,枚举要求我在编译时知道所有的消息类型,但是消息分布在多个库中。其中一些库是可选加载的,所以如果它们没有加载,我不想将它们包含在枚举中。
是否有一种方法可以在运行时定义一个类似于枚举的"常量集合"?
您不能使用enum
,但是有任何理由认为简单的Map
不能满足您的目的吗?或者,由于您有一些其他实用程序方法,由Map支持的类?您可以仅为已加载的库添加那些消息,如果在应用程序的加载阶段和运行阶段之间有明确的描述,您甚至可以使用构建器模式并将Map冻结为不可变映射,以便一旦应用程序运行,就不能对消息进行进一步更改。
(这可以用Collections.unmodifiableMap()
或Guava的不可变映射类型之一来完成)
我不完全清楚的一件事是,您是否保证在不同库使用的消息中不会发生冲突。这可能是一个问题。
例如:import java.util.HashMap;
import java.util.Map;
public class MessageType {
private final static Map<Long, MessageType> messageTypes = new HashMap<>();
// it isn't clear how the libraries would provide information on
// the message types they support; suppose that each library has a
// MessageInfo that implements Map<Long, String> with all its types:
public static void loadLibrary(MessageInfo messageInfo) {
// populate the map with each message type it supports
for (Map.Entry<Long, String> entry : messageInfo.entrySet()) {
MessageType messageType =
new MessageType(entry.getKey(), entry.getValue());
messageTypes.put(entry.getKey(), messageType);
}
}
// A MessageType has a name and a number
private final long number;
private final String name;
private MessageType(long number, String name) {
this.number = number;
this.name = name;
}
public long getMessageNumber() {
return number;
}
public String getMessageName() {
return name;
}
public static MessageType fromMessageNumber(long number) {
if (!messageTypes.containsKey(number)) {
throw new IllegalArgumentException("Unknown message: " + number);
}
return messageTypes.get(number);
}
}
您还可以添加检查以确保没有定义重复的消息类型,没有创建具有null
名称或数字的消息类型,并添加依赖于名称和数字的hashCode()
、equals(Object)
和toString()
方法。例如,
@Override
public String toString() {
return "message:" + name + "<" + number + ">";
}
或者您希望消息以任何方式显示以进行调试。请注意,因为每个消息类型只创建一个MessageType对象,所以将它们与==
进行比较应该是安全的,尽管您无法获得从Java enum
类型获得的强大保护。(仍然可以通过反射创建重复的MessageType
对象,或者,如果您将它们创建为Serializable
,则可以通过序列化和反序列化来创建它们)(这种方法,每个不同的值只创建一个实例,称为Flyweight设计模式,您可能知道。)