我有一个服务器应用程序,可以在ServerSocket
上侦听传入的查询。提交查询的客户端希望打开服务器的套接字,向上游传递查询,然后(可能在很短的一段时间后)从他们使用的相同的套接字读取对查询的响应提交查询。
为此,我尝试使用ExecutorCompletionService
。不同的查询类会传递给不同的Callable
,但所有查询类都会返回String
作为结果。
所有这些都是可以管理的,直到我到达实际尝试回复客户端的阶段。 Future
对象目前都是Future<String>
类型,但我无法将结果(String
)与相应的Socket
结合。
我的解决方案是让我的所有Callable
类型为Callable<StringSocketPair>
,其中StringSocketPair
看起来像;
public class StringSocketPair {
Socket sock;
String content;
}
但这一切似乎都有些奇怪,因为现在我必须将Socket
传递给Callable
构造函数,以便它可以将String
结果与call()
结果一起返回1}}方法。所有这些都是为了让我可以将String
推到另一个轮询Socket
的{{1}}中。
另一种选择是使用ExecutorCompletionService.take()
而不是Runnable
s并让每个Callable
任务自行回复Runnable
,但因为我有十几个左右查询类型,每个都有自己的任务对象,而且我不必为每个任务对象的每个Socket
方法的末尾添加某种respondToClient()
调用。
对于我认为相当常见的设置,必须有一个更简单的解决方案吗?
答案 0 :(得分:2)
遵循使用Runnable
的想法,您可以使用Template Method Pattern来定义响应功能。这将阻止您为每个任务编写公共代码,因为公共代码将放在实现Runnable的抽象父类中。
模板方法模式:
abstract class TemplateSuperClass implements Runnable {
public void run() {
//some setup code here
String message = taskWork(...);
socket.write(message);
//common cleanup code
}
abstract String taskWork(...);
}
class HelloWorld extends TemplateSuperClass {
String taskWork(...) {
return "Hello World";
}
}
否则,您可能更改Callable以返回响应消息和套接字的元组。