我正在开发的程序具有分布式体系结构,更准确地说是Broker-Agent模式。代理将向其相应的代理发送消息,以便告诉代理执行任务。发送的每条消息都包含目标任务信息(任务名称、执行任务所需的配置属性等)。在我的代码中,代理端的每个任务都是在单独的类中实现的。如:
public class Task1 {}
public class Task2 {}
public class Task3 {}
...
消息采用JSON格式,如
{
"taskName": "Task1", // put the class name here
"config": {
}
}
因此,我需要将从代理发送的消息与代理端的正确任务关联起来。
我知道一种方法是将目标任务类名称放在消息中,以便代理能够通过使用反射从消息中提取的任务名称创建该任务类的实例,如:
Class.forName(className).getConstructor(String.class).newInstance(arg);
我想知道实现这种关联的最佳实践是什么。任务的数量在增长,我认为写字符串很容易出错,也不容易维护。 如果你对类名有那么明确的要求,你甚至可以考虑序列化任务对象并直接发送它们。这可能比反射方法更简单(尽管耦合更紧密)。
但是通常你不希望Broker和Agent之间有这样的耦合。代理需要知道有哪些任务类型,以及如何以每个人都能理解的方式描述任务(比如JSON)。它不知道/不应该知道Agent如何实现任务。甚至不知道特工是用哪种语言写的。(这并不意味着在两个代码库通用的地方定义任务名是一个坏主意)
因此,您需要找到一种基于某个字符串在代理内部构造对象(或调用方法)的好方法。常见的解决方案是某种形式的工厂模式,如:http://alvinalexander.com/java/java-factory-pattern-example -也很有用:Map<String, Factory>
,如
interface Task {
void doSomething();
}
interface Factory {
Task makeTask(String taskDescription);
}
Map<String, Factory> taskMap = new HashMap<>();
void init() {
taskMap.put("sayHello", new Factory() {
@Override
public Task makeTask(String taskDescription) {
return new Task() {
@Override
public void doSomething() {
System.out.println("Hello" + taskDescription);
}
};
}
});
}
void onTask(String taskName, String taskDescription) {
Factory factory = taskMap.get(taskName);
if (factory == null) {
System.out.println("Unknown task: " + taskName);
}
Task task = factory.makeTask(taskDescription);
// execute task somewhere
new Thread(task::doSomething).start();
}
http://ideone.com/We5FZk 如果你想让它更花哨,考虑基于注释的反射魔法。取决于有多少个任务类。在自动解决方案中投入的努力越多,就会对您隐藏复杂性。
例如上面的Map
可以通过添加一些类路径扫描来自动填充正确类型的类,并添加一些包含字符串的注释。或者你可以让一些DI框架将所有需要的东西注入到映射中。大型项目中的DI通常可以很好地解决这些问题:https://softwareengineering.stackexchange.com/questions/188030/how-to-use-dependency-injection-in-conjunction-with-the-factory-pattern
除了编写自己的分发系统之外,您可能还可以使用现有的分发系统。(重用而不是重新发明是最佳实践)。也许http://www.typesafe.com/activator/template/akka-distributed-workers或更一般的http://twitter.github.io/finagle/适用于您的上下文。但是有太多其他的开源分布式的东西涵盖了不同的方面,以至于不能列出所有有趣的。