【问题标题】:How to load factory pattern dynamically from the map?如何从地图动态加载工厂模式?
【发布时间】:2016-12-11 01:44:45
【问题描述】:

我有各种类型的事件,如下所示。一般来说,我有更多的活动。

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  ----->  
  • 假设我在问题中的代码中将“EventA”作为 eventType,然后我会将 eventHolder Map 传递给一个方法(我们将其称为 QueryA)并在该方法中对此进行一些操作地图并返回一个新地图。然后这个新 Map 将被传递给另一个方法(我们称之为 QueryB),然后我们将再次对其进行一些操作,然后返回另一个 Map,然后该映射将返回给调用者。
  • 现在假设“EventB”在我的问题中的代码中作为 eventType 出现,然后我会将 eventHolder Map 传递给一个方法(我们将其称为 QueryA)并在该方法中,我将在此地图上执行一些操作并返回一个新地图。然后这个地图将被传回给调用者。
  • 现在假设“EventE”在我的问题中的代码中作为 eventType 出现,然后我会将 eventHolder Map 传递给 EventE 类,并且由于在这种情况下我们无需做任何事情,那么我将传递此映射因为它返回给调用者。

问题:

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

我事先知道所有的 eventType,因此我可以通过将其放入地图来静态初始化所有工厂,然后在我们运行代码时一旦 eventType 出现,我就可以从地图中加载各个工厂。

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

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

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

【问题讨论】:

  • 我知道一种非常 oop 的方式来做到这一点,而无需使用 if-else 或 switch,但不记得了。也许在早上睡个好觉之后。
  • 返回地图的目的是什么?

标签: java design-patterns interface factory-pattern abstract-factory


【解决方案1】:

嗯,这个问题有两个主要目标。

  • 引入和重用自定义查询逻辑。
  • 将 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;
  }
}

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

例如:QueryAB(需要 eventA)

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

现在您可以拥有一个Map&lt;String, Query&gt; eventToQueryMap,它会动态映射您的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.

然后,每当您收到 eventType 字符串时,您都想做的是。

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

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

【讨论】:

    【解决方案2】:

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

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

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

    但是,这样做对我来说有点矫枉过正。我认为一个简单的模板方法模式也会产生你所需要的。但是,这取决于您要对查询结果执行的操作。这是一个模板方法示例:

    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);
    

    如果您需要单独返回每个查询的每个 Map,您可以将模板方法的返回类型更改为 List&lt;Map&lt;String, String&gt;&gt;

    【讨论】:

    • 让我们讨论here。我对这种方法有点困惑。我会向你解释我到底想要做什么。
    【解决方案3】:

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

    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();
    

    【讨论】:

    • 嘿,你在附近。我对这种方法有点困惑。我在这个聊天room。让我们在这里讨论。
    猜你喜欢
    • 1970-01-01
    • 2020-08-03
    • 1970-01-01
    • 2022-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-02
    • 2023-04-10
    相关资源
    最近更新 更多