如何从地图动态加载工厂模式?

How to load factory pattern dynamically from the map?

我有各种类型的事件,如下所示。总的来说我的活动比较多。

EventA
EventB
EventC
EventD
EventE

下面是我将获取每个事件类型的代码:

  public void run() {
    try {
      while (!closed.get()) {
        ConsumerRecords records = consumer.poll(10000);
        // Handle new records
        for (ConsumerRecord<String, String> record : records) {
          GenericRecord payload = decoder.decode(record.value());
          String eventType = String.valueOf(payload.get("eventType"));
          String eventMapHolder = String.valueOf(payload.get("eventMapHolder"));
          Map<String, String> eventHolder = parseStringToMap(eventHolder);
          // here eventType will "EventA", "EventB" and so on
          // pass eventType to get the individual factory for that event type
          // and then  pass eventHolder to a particular method of that factory class which calls appropriate Query method.
        }
      }
    } catch (Exception e) {
        // log error
    }
  }

对于每个事件,我需要执行不同的数据库查询,但至少对于大多数事件,我需要执行一个对所有事件都通用的数据库查询。例如:

EventA  -----> QueryA, QueryB
EventB  -----> QueryA
EventC  -----> QueryA, QueryC
EventD  -----> QueryA, QueryD
EventE  ----->

流程如下:

                    EventA  ----->  QueryA, QueryB
                    EventB  ----->  QueryA
eventHolder         EventC  ----->  QueryA, QueryC
                    EventD  ----->  QueryA, QueryD
                    EventE  ----->  

问题:

对于这种问题,我应该使用哪种设计模式?我想避免使用 if/else 或在此处切换 bcoz 一般来说,我有很多事件类型,因此考虑为它们创建一个单独的工厂,我们可以通过传递 eventType 值在运行时动态加载它。

我事先知道所有的事件类型,所以我可以通过将它放在地图中来静态初始化所有工厂,然后一旦事件类型出现,而我们是 运行 代码,我可以从地图加载各个工厂.

如果这是解决此问题的正确设计模式,我如何在此处使用抽象工厂模式来完成此任务?我想将 "eventType" 作为键传递给工厂,该工厂将 return 该事件类型的实例。所以假设我将 "EventA" 传递给工厂,然后它将 return 工厂 class 传递给 "EventA",然后我们将在 class 上调用一个特定的方法它在内部调用 QueryA 方法,然后我们调用 QueryB 方法,最后它将 return 映射,我将在上面的代码中将其打印出来。其他事件类型也类似。

基于这个原因,我在想一些事情:我不确定工厂模式是否完全可行,或者是否可能是其他设计模式。 (我的命名约定可能搞砸了,我只是想出了下面的名字)

EventFactory eventFactory = EventTypeFactory.getInstance().getFactory(eventType);
Map<String, String> holder = eventFactory.execute(eventHolder);

我不确定我是否明白你的意思。您只需要一次工厂模式来初始化处理您的事件的对象。工厂是一种创建模式,与查询的执行无关。所以基本上你的方法是部分正确的:

Object o = EventTypeFactory.getInstance().getFactory(eventType);

这是可以使用工厂的地方。我故意使用 Object 作为类型,因为我们现在要讨论哪种模式最适合 "event handling"。首先它必须是一种行为模式。我会说命令模式可以派上用场。但是,您可能还需要迭代器模式来表示每个事件的潜在不同查询量。

然而,这样做对我来说有点矫枉过正。我认为一个简单的模板方法模式也可以满足您的需求。但是,这取决于您要对查询结果执行的操作。这是一个模板方法示例:

public abstract class EventHandler {
   public abstract Collection<String> getQueries();

   public Map<String, String> handleEvent(Map<String, String> eventData) {
      Map<String, String> result = new HashMap<>();

      for(String query : getQueries()) {
         // execute the query and merge the query result into the result map
      }

      return result;
   }
}

public class EventAEventHandler extends EventHandler {
   public abstract Collection<String> getQueries() {
      List<String> queries = new ArrayList<>();

      queries.add("YourQueryHere");

      return queries;
   }
}

处理一个事件:

EventHandler handler = EventTypeFactory.getInstance().getFactory(eventType);
Map<String, String> holder = handler.execute(eventMap);

如果您需要为每个查询单独 returned 您可以将模板方法的 return 类型更改为 List<Map<String, String>>.

据我了解,你好像不需要工厂模式。你可以有一个像下面这样的枚举:

public enum Event {

  EventA {
    @Override
    Map<String, String> executeQuery() {
      final Map<String, String> map = super.executeQuery();
      executeQueryB();
      return map;
    }

    private void executeQueryB() {

    }
  },
  EventB,
  EventC,
  EventD,
  ;

  Map<String, String> executeQuery() {
  }

}

像下面这样使用就足够了:

return Event.valueOf("EventA").executeQuery();

好吧,这道题主要有两点要实现。

  • 引入并重新使用自定义查询逻辑。
  • 将 eventType 字符串动态映射到相关查询操作。

首先我更喜欢你 采用 Interpreter 模式的变体。所以它看起来像这样。

public interface Query{
  public Map<String, String> execute(Map<String, String> map);
} 

@Singleton
public class QueryA implements Query{
  @Override
  public Map<String, String> execute(Map<String, String> map){
    //queryA logic.
  }
}     

public class CustomQuery implements Query{
  List<Query> queryList;

  public void CustomQuery(List<Query> queries){
    this.queryList = queries;
  }

  public void CustomQuery(Query query1, Query query2){
    this.queryList = new ArrayList();
    queryList.add(query1);
    queryList.add(query2);
  }

  @Override
  public Map<String, String> execute(Map<String, String> map){
    if(queryList == null){
         return map;
    }

    Map<String, String> eventMap = map;
    for(Query query: queryList){
        eventMap = query.execute(eventMap);
    }
    return eventMap;
  }
}

请注意,每个 子查询 class(例如:QueryA)应该是 Singleton 以避免内存占用。使用上面我们可以有自定义查询操作。

例如:QueryAB(事件 A 的需要)

@Inject
QueryA queryA;
@Inject
QueryB queryB;
Query queryAB = new CustomQuery(queryA, queryB);

现在您可以拥有一个 Map<String, Query> eventToQueryMap 动态 maps 您的 EventType 转化为必要的QueryLogic(s).

例如:

Map<String, Query> eventToQueryMap = new HashMap();
eventToQueryMap.put("EventA", queryAB);
eventToQueryMap.put("EventB", queryA);
//like above you can add for others too.

然后每当你收到你的事件类型字符串时,你都想做的是。

Map<String, String> eventMap = eventToQueryMap.get(eventType).execute(eventHolder);

这是您遇到的主要问题的大纲解决方案。您可以自己添加自定义。 :))