我有一个Java客户端,希望通过串行通信的消息与设备通信。客户端应该能够使用干净的API,抽象出串行通信的丑陋细节。客户端可以通过该API发送许多类型的消息并获得响应。我正在寻找建议哪种方式最适合实施此API。
为简单起见,我们只提供两种消息类型:HelloMessage
触发HelloResponse
和InitMessage
触发InitResponse
(实际上还有更多)
设计API(即设备的Java抽象)我可以:
每种消息类型一种方法:
public class DeviceAPI {
public HelloResponse sendHello(HelloMessage){...}
public InitResponse sendInit(InitMessage){...}
... and many more message types ....
这很安全。 (它也可能是同一send()
方法的多次重载,但这个方法大致相同。但它非常明确,而且不够灵活 - 我们无法在不修改API的情况下添加消息。
我也可以使用一个send方法,它接受所有消息类型:
class HelloMessage implements Message
class HelloResponse implements Response
...
public class DeviceAPI {
public Response send(Message msg){
if(msg instanceof HelloMessage){
// do the sending, get the response
return theHelloResponse
} else if(msg instanceof ...
这简化了API(只有一种方法),并允许在以后添加其他消息类型而无需更改API。同时,它要求客户端检查响应类型并将其转换为正确的类型。
客户代码:
DeviceAPI api = new DeviceAPI();
HelloMessage msg = new HelloMessage();
Response rsp = api.send(msg);
if(rsp instanceOf HelloResponse){
HelloResponse hrsp = (HelloResponse)rsp;
... do stuff ...
在我看来这很难看。
你推荐什么?还有其他方法可以提供更清晰的结果吗?
欢迎参考!别人怎么解决这个问题?
答案 0 :(得分:2)
我现在已经有了一个完全正常的例子:
定义消息类型:
public interface MessageType {
public static class INIT implements MessageType { }
public static class HELLO implements MessageType { }
}
基础Message
和Response
类:
public class Message<T extends MessageType> {
}
public class Response<T extends MessageType> {
}
创建自定义初始化消息和响应:
public class InitMessage extends Message<MessageType.INIT> {
public InitMessage() {
super();
}
public String getInit() {
return "init";
}
}
public class InitResponse extends Response<MessageType.INIT> {
public InitResponse() {
super();
}
public String getInit() {
return "init";
}
}
创建自定义问候消息和响应:
public class HelloMessage extends Message<MessageType.HELLO> {
public HelloMessage() {
super();
}
public String getHello() {
return "hello";
}
}
public class HelloResponse extends Response<MessageType.HELLO> {
public HelloResponse() {
super();
}
public String getHello() {
return "hello";
}
}
DeviceAPI
:
public class DeviceAPI {
public <T extends MessageType, R extends Response<T>, M extends Message<T>> R send(M message) {
if (message instanceof InitMessage) {
InitMessage initMessage = (InitMessage)message;
System.out.println("api: " + initMessage.getInit());
return (R)(new InitResponse());
}
else if (message instanceof HelloMessage) {
HelloMessage helloMessage = (HelloMessage)message;
System.out.println("api: " + helloMessage.getHello());
return (R)(new HelloResponse());
}
else {
throw new IllegalArgumentException();
}
}
}
请注意,它确实需要instanceof
- 树,但您需要它来处理它是什么类型的消息。
一个有效的例子:
public static void main(String[] args) {
DeviceAPI api = new DeviceAPI();
InitMessage initMsg = new InitMessage();
InitResponse initResponse = api.send(initMsg);
System.out.println("client: " + initResponse.getInit());
HelloMessage helloMsg = new HelloMessage();
HelloResponse helloResponse = api.send(helloMsg);
System.out.println("client: " + helloResponse.getHello());
}
输出:
api: init
client: init
api: hello
client: hello
更新:添加了有关如何从客户端要发送的消息中获取输入的示例。
答案 1 :(得分:1)
您可以拥有一个消息处理程序系统,您的DeviceAPI可以选择哪个处理程序适合传入消息;并将其委托给适当的消息处理程序:
class DeviceAPI {
private List<Handler> msgHandlers = new ArrayList<Handler>();
public DeviceAPI(){
msgHandlers.add(new HelloHandler());
//Your other message handlers can be added
}
public Response send(Message msg) throws Exception{
for (Handler handler : msgHandlers) {
if (handler.canHandle(msg)){
return handler.handle(msg);
}
}
throw new Exception("No message handler defined for " + msg);
}
}
HelloHandler看起来像:
interface Handler<T extends Message, U extends Response> {
boolean canHandle(Message message);
U handle(T message);
}
class HelloHandler implements Handler<HelloMessage, HelloResponse> {
@Override
public boolean canHandle(Message message) {
return message instanceof HelloMessage;
}
@Override
public HelloResponse handle(HelloMessage message) {
//Process your message
return null;
}
}
同样适用于您的其他消息。我相信你可以让它更优雅,但这个想法仍然保持不变 - 不要用ifs的怪物方法;而是使用多态。
答案 2 :(得分:1)
以下是使用泛型以类型安全(和可扩展)方式执行此操作的方法:
public interface MessageType {
public static final class HELLO implements MessageType {};
}
public interface Message<T extends MessageType> {
Class<T> getTypeClass();
}
public interface Response<T extends MessageType> {
}
public class HelloMessage implements Message<MessageType.HELLO> {
private final String name;
public HelloMessage(final String name) {
this.name = name;
}
@Override
public Class<MessageType.HELLO> getTypeClass() {
return MessageType.HELLO.class;
}
public String getName() {
return name;
}
}
public class HelloResponse implements Response<MessageType.HELLO> {
private final String name;
public HelloResponse(final String name) {
this.name = name;
}
public String getGreeting() {
return "hello " + name;
}
}
public interface MessageHandler<T extends MessageType, M extends Message<T>, R extends Response<T>> {
R handle(M message);
}
public class HelloMessageHandler
implements MessageHandler<MessageType.HELLO, HelloMessage, HelloResponse> {
@Override
public HelloResponse handle(final HelloMessage message) {
return new HelloResponse(message.getName());
}
}
import java.util.HashMap;
import java.util.Map;
public class Device {
@SuppressWarnings("rawtypes")
private final Map<Class<? extends MessageType>, MessageHandler> handlers =
new HashMap<Class<? extends MessageType>, MessageHandler>();
public <T extends MessageType, M extends Message<T>, R extends Response<T>>
void registerHandler(
final Class<T> messageTypeCls, final MessageHandler<T, M, R> handler) {
handlers.put(messageTypeCls, handler);
}
@SuppressWarnings("unchecked")
private <T extends MessageType, M extends Message<T>, R extends Response<T>>
MessageHandler<T, M, R> getHandler(final Class<T> messageTypeCls) {
return handlers.get(messageTypeCls);
}
public <T extends MessageType, M extends Message<T>, R extends Response<T>>
R send(final M message) {
MessageHandler<T, M, R> handler = getHandler(message.getTypeClass());
R resposnse = handler.handle(message);
return resposnse;
}
}
public class Main {
public static void main(final String[] args) {
Device device = new Device();
HelloMessageHandler helloMessageHandler = new HelloMessageHandler();
device.registerHandler(MessageType.HELLO.class, helloMessageHandler);
HelloMessage helloMessage = new HelloMessage("abhinav");
HelloResponse helloResponse = device.send(helloMessage);
System.out.println(helloResponse.getGreeting());
}
}
要添加对新消息类型的支持,请实现MessageType
接口以创建新消息类型,为新Message
实现Response
和MessageHandler
接口1}}类并通过调用MessageType
来注册新消息类型的处理程序。
答案 3 :(得分:0)
我认为这根本不丑:
if(rsp instanceOf HelloResponse){
HelloResponse hrsp = (HelloResponse)rsp;
...
else if ...
只要你没有100个不同的回答。您可以将多种响应封装在一起,具体取决于它们具有的数据。例如:
class GenericResponse{
private String message;
private int responseType;
...
}
我开发了一些多人游戏,这是一个很好的方法。 如果你有太多不同类型的消息,你可以使用通用的java类型,比如上面的skiwi示例。
希望有所帮助