java 泛型设计问题(状态机)
我做了一个状态机,并希望它利用java中的泛型。目前,我没有看到如何使这项工作并得到漂亮的代码。我确定这个设计问题以前已经解决过很多次了,我正在寻找一些输入。这是一个粗略的轮廓。
class State { ... }
每个不同状态对象只有一个副本(主要是与静态最终变量绑定的匿名类),它具有每个状态的自定义数据。每个状态对象都有一个状态父级(有一个根状态)
class Message { ... }
每条消息都是单独创建的,并且每条消息都有自定义数据。它们可以相互细分。有一个根邮件类。
class Handler { ... }
每个处理程序仅创建一次,并处理特定的状态/消息组合。
class StateMachine { ... }
当前跟踪当前状态,以及所有 (,) ->映射的列表。它还具有其他功能。我试图保持这个类的泛型,并用类型参数子类化它,因为它在我的程序中使用了很多次,每次使用不同的's/'s/和's.不同的's将有不同的参数到他们的处理程序。State
Message
Handler
Message
State
Handler
StateMachine
方法 A
让状态机跟踪所有映射。
class StateMachine<MH extends MessageHandler> {
static class Delivery {
final State state;
final Class<? extends Message> msg;
}
HashMap<Delivery, MH> delegateTable;
...
}
class ServerStateMachine extends StateMachine<ServerMessageHandler> {
...
}
允许我为这个特定的状态机提供自定义处理程序方法。可以覆盖 handler.process 方法的参数。但是,不能按消息类型参数化处理程序。
问题:这涉及对每个消息处理程序使用健全性检查(确保它正在获取预期的消息)。instanceof
方法 B
允许按消息类型参数化每个消息处理程序
class MessageHandler<M extends Message> {
void process(M msg) { .... }
}
问题:类型擦除将阻止我将这些存储在一个漂亮的哈希映射中,因为所有's的类型都将以不同的方式输入。如果我可以将它们存储在地图上,我将无法回复它们并使用适当的参数调用它们。MessageHandler
方法 C
让状态对象处理所有消息。
class State<M extends Message> { ... }
class ServerState<M extends ServerMessage> extends State<M> { ... }
我有消息处理程序绑定到特定的状态机状态(通过将它们放在里面),(状态机的每个实例都有自己的有效状态列表),这允许处理程序属于特定类型。(服务器状态机 ->服务器消息处理程序)。
问题:每个状态只能处理一种消息类型。您还失去了父状态可以处理与子状态不同的消息的想法。类型擦除还会阻止 调用当前状态进程方法。StateMachine
方法 D
使消息的进程本身基于状态。
问题:从未真正考虑过,因为每个消息都应该有一个基于当前状态机状态的不同处理程序。发送者将不知道当前状态。StateMachine
方法 E
忘记泛型和硬代码状态/消息处理与 switch 语句。
问题:理智
不安全的解决方案:
感谢您的输入大家,我认为问题是我没有把它简化为好问题(太多的讨论)这就是我现在所拥有的。
public class State { }
public class Message { }
public class MessageHandler<T extends Message> { }
public class Delivery<T extends Message> {
final State state;
final Class<T> msgClass;
}
public class Container {
HashMap<Delivery<? extends Message>, MessageHandler<? extends Message>> table;
public <T extends Message> add(State state, Class<T> msgClass, MessageHandler<T> handler) {
table.put(new Delivery<T>(state, msgClass), handler);
}
public <T extends Message> MessageHandler<T> get(State state, T msg) {
// UNSAFE - i cannot cast this properly, but the hashmap should be good
MessageHandler<T> handler = (MessageHandler<T>)table.get(new Delivery<T>(state, msg.getClass()));
return handler;
}
}