我正在开发的程序有一个分布式架构,更确切地说是Broker-Agent Pattern。代理将向其相应的代理发送消息,以告知代理执行任务。发送的每条消息都包含目标任务信息(任务名称,任务执行所需的配置属性等)。在我的代码中,代理端的每个任务都是在一个单独的类中实现的。喜欢:
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);
我想知道实现此关联的最佳做法是什么。任务的数量正在增长,我认为编写字符串很容易出错并且不易维护。
答案 0 :(得分:1)
如果您具体了解类名,您甚至可以考虑序列化任务对象并直接发送它们。这可能比你的反射方法更简单(尽管更紧密耦合)。
但通常你不想要Broker和Agent之间的那种耦合。代理需要知道哪些任务类型以及如何以每个人都理解的方式描述任务(如在JSON中)。它不知道/不应该知道代理如何实现任务。甚至是代理编写的语言。 (这并不意味着在两个代码库共有的地方定义任务名称是个坏主意)
因此,您可以根据某些字符串找到在代理中构建对象(或调用方法)的好方法。对此的常见解决方案是某种形式的工厂模式,例如: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();
}
如果你想要它,可以考虑基于注释的反射魔法。取决于有多少任务类。投入自动化解决方案的努力越多,就越能隐藏您的复杂性。
例如,上面Map
可以通过为正确类型的类添加一些class path scanning并使用一些包含字符串的注释来自动填充。或者你可以让一些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/可以在您的上下文中使用。但是有太多其他开源分布式的东西,涵盖不同的方面,以命名所有有趣的。