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

时间:2016-12-11 01:44:46

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

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

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  ----->  
  • 所以,让我说我得到&#34; EventA&#34;作为我在我的问题中的代码中的eventType,然后我将eventHolder Map传递给一个方法(让我们称之为QueryA),在该方法中,我将在这个地图上做一些操作并返回一个新的Map。然后这个新的Map将被传递给另一个方法然后(让我们调用QueryB)然后我们再对它做一些操作,然后返回另一个Map,然后该地图将返回给调用者。
  • 现在让我们说&#34; EventB&#34;在我的问题代码中将eventType作为eventType,然后我将eventHolder Map传递给一个方法(让我们称之为QueryA),在该方法中,我将在这个地图上做一些操作并返回一个新的Map 。然后这张地图将传回给来电者。
  • 现在让我们说&#34; EventE&#34;在我的问题代码中有eventType作为eventType,然后我将eventHolder Map传递给EventE类,并且因为我们不需要为这种情况做任何事情,所以我会将这个地图传递给调用者。< / LI>

问题:

我应该使用哪种设计模式来解决这类问题?我想避免使用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);

3 个答案:

答案 0 :(得分:1)

嗯,在这个问题上有两件事要做。

  • 介绍&amp;重用自定义查询逻辑。
  • 将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)应为 Singleton ,以避免记忆足 - 打印。使用上面我们可以进行自定义查询操作。

ex:QueryAB(需要eventA)

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

现在,您可以拥有Map<String, Query> eventToQueryMap动态 地图 EventType < em>进入 必要的 QueryLogic

前:

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

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

答案 1 :(得分:0)

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

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

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

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

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<Map<String, String>>

答案 2 :(得分:0)

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

import Foundation

let data = Data(bytes: [24, 163, 209, 194, 255, 1, 184, 230, 37, 208, 140, 201, 6, 0, 64, 0, 7, 98, 108, 117])

let dataStream = InputStream(data: data)
dataStream.open()

let numBytesPerObject = 2
var buffer = [UInt8](repeating: 0, count: numBytesPerObject)

while dataStream.read(&buffer, maxLength: numBytesPerObject) != 0 {
    print(buffer)
}

使用以下就足够了:

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() {
  }

}