关联消息和目标 class 实例创建的最佳实践

Best practice to associate message and target class instance creation

我正在开发的程序具有分布式架构,更准确地说是 Broker-Agent 模式。代理将向其相应的代理发送消息,以告知代理执行任务。发送的每条消息都包含目标任务信息(任务名称、任务执行所需的配置属性等)。在我的代码中,代理端的每个任务都是在单独的 class 中实现的。喜欢:

public class Task1 {}
public class Task2 {}
public class Task3 {}
...

消息采用 JSON 格式,例如:

{
  "taskName": "Task1",  // put the class name here
  "config": {

  }
}

所以我需要的是将代理发送的消息与代理端的正确任务相关联。

我知道一种方法是将目标任务 class 名称放在消息中,以便代理能够通过从消息中提取的任务名称创建该任务的实例 class使用反射,例如:

Class.forName(className).getConstructor(String.class).newInstance(arg);

我想知道实施此关联的最佳做法是什么。任务越来越多,我觉得写string容易出错,也不好维护。

如果您对类名特别在意,您甚至可以考虑序列化任务对象并直接发送它们。这可能比您的反射方法更简单(尽管耦合更紧密)。

但通常您不希望 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可以通过添加一些class path scanning for classes of the right type with some annotation that holds the string(s). Or you could let some DI framework inject all the things that need to go into the map. DI in larger projects usually solves those kinds of issues really well: 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 or more general http://twitter.github.io/finagle/ 在您的上下文中工作。但是有太多其他开源分布式东西涵盖了不同的方面,无法列举出所有有趣的东西。