Как динамически загрузить фабричный шаблон с карты?
У меня есть различные типы событий, как показано ниже. В общем у меня больше событий.
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), и в рамках этого метода я сделаю некоторую операцию с этой картой и верну новая карта. И затем эта новая Карта будет передана другому методу (давайте назовем этот QueryB), а затем снова мы сделаем некоторую операцию над этим, а затем вернем другую Карту, а затем эта карта вернется к вызывающей стороне.
- Теперь предположим, что "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);
3 ответа
Что ж, в этом вопросе есть две основные вещи.
- Внедрить и повторно использовать пользовательские логики запросов.
- Динамически сопоставить eventType String с соответствующими действиями запроса.
Во-первых, я предпочитаю, чтобы вы приняли вариант шаблона интерпретатора. Так бы это выглядело так.
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, чтобы избежать отпечатка памяти. Используя выше, мы можем иметь пользовательские действия запроса.
например: QueryAB (требуется для eventA)
@Inject
QueryA queryA;
@Inject
QueryB queryB;
Query queryAB = new CustomQuery(queryA, queryB);
Теперь вы можете иметь Map<String, Query> 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 String, то, что вы все хотите сделать, это.
Map<String, String> eventMap = eventToQueryMap.get(eventType).execute(eventHolder);
Это общее решение для вашей основной проблемы. Вы можете добавить настройки по своему усмотрению.:))
Я не уверен, что понял вашу точку зрения. Чтобы инициализировать объект, обрабатывающий ваше событие, вам нужен только фабричный шаблон. Фабрика - это творческий шаблон, который не имеет ничего общего с выполнением запросов. Так что в принципе ваш подход частично верен:
Object o = EventTypeFactory.getInstance().getFactory(eventType);
Это точка, где фабрика может быть использована. Я специально использую Object как тип, так как сейчас мы собираемся обсудить, какой шаблон лучше всего подходит для "обработки событий". Прежде всего это должен быть поведенческий паттерн. Я бы сказал, что шаблон 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);
Если вам нужна каждая карта для каждого отдельно возвращаемого запроса, вы можете изменить тип возвращаемого значения метода шаблона на 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();