对于我的Java游戏服务器,我发送数据包的操作ID,该操作ID基本上告诉服务器该数据包的目的。我想将每个操作ID(整数)映射到功能。有没有使用开关的方法?

有帮助吗?

解决方案

这个如何?

HashMap<Integer, Runnable> map = new HashMap<Integer, Runnable>();
map.put(Register.ID, new Runnable() { 
    public void run() { functionA(); }
});
map.put(NotifyMessage.ID, new Runnable() { 
    public void run() { functionB(); }
});
// ...
map.get(id).run();

(如果您需要传递一些参数,请使用具有合适参数的函数来定义自己的接口,并使用该函数而不是可运行)。

其他提示

Java实际上没有功能指针(我们得到了匿名的内部类)。但是,只要您打开价值而不是类型,使用开关确实没有错。您是否有某种原因不想使用开关?似乎您必须在代码中某个地方的操作ID和操作之间进行映射,所以为什么不简单呢?

Java没有一流的功能指针。为了实现类似的功能,您必须定义和实现接口。您可以使用匿名内部类使它变得更容易,但是它仍然不是很漂亮。这是一个例子:

public interface PacketProcessor
{
    public void processPacket(Packet packet);
}

...

PacketProcessor doThing1 = new PacketProcessor()
{
    public void processPacket(Packet packet)
    {
        // do thing 1
    }
};
// etc.

// Now doThing1, doThing2 can be used like function pointers for a function taking a
// Packet and returning void

您是否曾经使用过摇摆/aw?他们的事件层次结构解决了类似的问题。 Java通过函数的方式与接口有关

public interface ActionHandler {
    public void actionPerformed(ActionArgs e);
}

然后,如果要将整数映射到这些对象上,则可以使用类似的东西 java.util.HashMap<Integer,ActionHandler> 管理这一点。实际的实现可以在匿名类(Java的最佳lambda”中进行,也可以在某个地方的适当类中进行。这是匿名类方法:

HashMap<Integer,ActionHandler> handlers;
handlers.put(ACTION_FROB, new ActionHandler() {
    public void actionPerformed(ActionArgs e) {
        // Do stuff
        // Note that any outer variables you intend to close over must be final.
    }
});
handlers.get(ACTION_FROB).actionPerformed(foo);

(编辑)如果您想更加虐待,可以这样初始化hashmap:

HashMap<Integer,String> m = new HashMap<Integer,String>() {{
    put(0,"hello");
    put(1,"world");
}};

是的,但是使用接口意味着您必须为每个回调创建一个接口,这意味着您要通过它设置的每个功能。创建一个代表类来处理此操作会给您(不是真正的功能指针),而是要传递的功能,如果您滥用通用的返回类型,则不必施放将瓶颈切成几乎一无所有的。

C#委托(MulticastDelegate要正确)从使用Method MethodInfo中获取信息,这与使用Java.lang.reflect.reflect.method为委托类需要做的事情。我在本网站的另一种形式的代表(t)类中发布了我的代码,以处理此问题。我之所以这样做,是因为(是)来自C ++,我需要一种更好的方法来传递功能(尤其是void),然后必须创建一个on函数或更多函数的接口。现在,我可以在其参数信息中选择填充功能。瞧!不错,可用,没有明显的速度从JIT或JVM损失。而且,如果我确实只学习Java编程仅一周,那么任何Java程序员都可以做到。

另外,在创建基本侦听器和基本界面时,它可以很好地传递在侦听器中。不再需要写另一个侦听器,因为该函数的名称已更改。创建代表班具有很大的优势,这是非常有用的和可通过的。

您可以接口静态方法。此方法也允许您指定参数。声明您的界面...

public interface RouteHandler {
    void handleRequest(HttpExchange t) throws IOException;
}

和你的地图...

private Map<String, RouteHandler> routes = new HashMap<>();

然后实现与接口/参数匹配的静态方法...

public static void notFound(HttpExchange t) throws IOException {
    String response = "Not Found";

    t.sendResponseHeaders(404, response.length());
    OutputStream os = t.getResponseBody();
    os.write(response.getBytes());
    os.close();
}

然后,您可以将这些方法添加到地图中...

routes.put("/foo", CoreRoutes::notFound);

并称他们如下...

RouteHandler handler = routes.get("/foo");
handler.handleRequest(exchange);

另一个类似的侵犯可能是使用Java 8的供应商:

Map<Integer, Supplier<T> suppliers = new HashMap();
suppliers.put(1, () -> methodOne());
suppliers.put(2, () -> methodTwo());

// ...

public T methodOne() { ... }
public T methodTwo() { ... }

// ...

T obj = suppliers.get(id).run();

您可以通过使用责任链模式来做到这一点。

这是一种将不同对象链接到链接列表的模式。 IE每个对象都对链中的下一个进行引用。链中的对象通常会处理一种特定的行为。对象之间的流量与开关案例语句非常相似。

有一些陷阱,例如,它传播您的逻辑,一个过长的链条会导致性能问题。但是,与这些陷阱一起,您可以通过提高可测试性和更强的凝聚力。另外,您不仅限于使用枚举,字节,int短和字符表达式作为分支的触发因素。

检查关闭如何在Lambdaj库中实现的方法。他们实际上的行为与C#委托非常相似:

http://code.google.com/p/lambdaj/wiki/closures

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top