Шаблон проектирования Java для обработки событий с различными типами? - PullRequest
1 голос
/ 25 июня 2019

Я хотел бы обобщить некоторый код, который реализует обработку событий наивным способом.У меня есть несколько типов событий, все имеют одни и те же базовые атрибуты, а также атрибуты, которые являются уникальными для каждого типа.События поступают в формате Json с атрибутом, который обозначает их тип.например:

{id:1, baseAttribute1:X1, baseAttribute2:Y1, type:eventA, eventAattribute1:Z, eventAattribute2:Q}

{id:2, baseAttribute1:X2, baseAttribute2:Y2, type:eventB, eventBattribute1:ZZ, eventBattribute2:QQ}

Я пытаюсь написать что-то общее, что позволит мне реализовать общую обработку отдельно от конкретного, но если я использую некоторый базовый объект BaseEvent, который eventA и eventB расширяетfrom - затем, в методе фабрики, например, я теряю тип события и не могу переслать его на правильный вызов, поэтому я не могу добавить doStuff(EventA a) и doStuff(EventB b), потому что объект имеет тип BaseEvent.

Ответы [ 2 ]

2 голосов
/ 25 июня 2019

Я должен был реализовать аналогичную вещь ранее, и вот что я сделал.

1. JSON в POJO

Вы можете использовать библиотеку Джексона json mapper для сопоставления полиморфного json с pojo. Вам потребуется базовый класс с производными классами для определенных типов событий. наследство Джексона

2. Шаблоны обработки событий и цепочки ответственности

Использовать шаблон проектирования цепочки ответственности. Имейте классы обработчика событий, соответствующие каждому из ваших типов событий. Каждый обработчик событий должен иметь метод проверки безопасности, который должен возвращать истину / ложь в зависимости от того, может ли он обрабатывать этот конкретный тип события или нет. Другой метод в этих обработчиках событий должен иметь код для действия с этим событием. Если обработчик события не способен обработать этот конкретный тип события, он должен перейти к следующему обработчику события. Схема проектирования цепочки ответственности

Кроме того, вы также можете изучить шаблон проектирования Observer. Шаблон проектирования наблюдателя

Пример (схема проектирования цепочки ответственности)

Ниже приведен короткий пример, демонстрирующий то же самое. Вы можете выполнить его рефакторинг, создав для вас цепочку создания фабрики и переместив проверки instanceof и вызвав следующий обработчик в методе-оболочке базового класса обработчика.

import java.util.*;
import java.lang.*;
import java.io.*;

class Ideone {
    public static void main (String[] args) throws java.lang.Exception {
        DogHandler dogHandler = new DogHandler(null);
        CatHandler catHandler = new CatHandler(dogHandler);

        AnimalHandler animalHandler = catHandler;

        Dog d = new Dog();
        Cat c = new Cat();

        animalHandler.apply(d);
        animalHandler.apply(c);

    }

    static abstract class Animal {
        public void print() {
            System.out.println("Animal");
        }
    }

    static class Dog extends Animal {
        public void print() {
            System.out.println("Dog");
        }

        public void dogMethod() {
            System.out.println("Dog specific method");
        }
    }

    static class Cat extends Animal {
        public void print() {
            System.out.println("Cat");
        }

        public void catMethod() {
            System.out.println("Cat specific method");
        }
    }

    static abstract class AnimalHandler {
        AnimalHandler nextHandler;

        public AnimalHandler(AnimalHandler nextHandler) {
            this.nextHandler = nextHandler;
        }

        public abstract void apply(Animal a);
    }

    static class DogHandler extends AnimalHandler {

        public DogHandler(AnimalHandler nextHandler) {
            super(nextHandler);
        }

        public void apply(Animal a) {
            if (a instanceof Dog) {
                Dog d = (Dog) a;
                d.dogMethod();
            } else {
                nextHandler.apply(a);
            }
        }
    }

    static class CatHandler extends AnimalHandler {

        public CatHandler(AnimalHandler nextHandler) {
            super(nextHandler);
        }

        public void apply(Animal a) {
            if (a instanceof Cat) {
                Cat c = (Cat) a;
                c.catMethod();
            } else {
                nextHandler.apply(a);
            }
        }
    }
}

Примечание. Если у вас есть несколько обработчиков событий, действующих на событие последовательно, выберите цепочку ответственности. Если есть какой-либо обработчик события, действующий в отношении данного события, лучше иметь Map<Class, EventHandler>, как указано в комментарии под моим ответом или шаблоном Observer.

1 голос
/ 25 июня 2019

Если вы хотите иметь один класс обработчика с несколькими методами :

Вы можете просто использовать огромный if-else или использовать Reflection

if-else:

public void handle(Event event){
    if(event instanceOf(EventA)){
        handleEventA();
    }
    else if(event instanceOf(EventB)){
        handleEventA();
    }
    //...
    else{
        handleDefaultEvent();
    }
}

Отражение:

package com.stackoverflow.q56754275.single_class;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class HandlerController {
    private Handler handler;
    public HandlerController(Handler handler) {
        this.handler=handler;
    }
    @SuppressWarnings("unchecked")
    public void handle(Event event) {
        Class<? extends Event> eventClass=event.getClass();
        Class<?> handlerClass=handler.getClass();
        Method handlerMethod=null;
        while(eventClass!=null&&!eventClass.equals(Object.class)) {

            try {
                handlerMethod = handlerClass.getMethod("handle", eventClass);
                handlerMethod.invoke(handler, event);
                break;
            } catch (NoSuchMethodException | IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
            }
            Class<?> superCl=eventClass.getSuperclass();

            if (superCl!=null) {
                eventClass=(Class<? extends Event>) superCl;
            }

        }
    }
}
package com.stackoverflow.q56754275.single_class;

public interface Handler {
    void handle(Event event);
}
package com.stackoverflow.q56754275.single_class;

public class Event {

}
package com.stackoverflow.q56754275.single_class;

public class SampleEventHandler implements Handler{

    @Override
    public void handle(Event event) {//default Handler

    }
    public void handle(EventA event) {//Handler for EventA

    }

    private static class EventA extends Event{

    }
}

Если вы хотите hava класс для каждого обработчика :

Вы можете создать Map<Class<? extends Event>,Handler> в порядкенайти обработчики событий.

package com.stackoverflow.q56754275.multiple_classes;

import java.util.HashMap;
import java.util.Map;

public class EventController {
    private Map<Class<? extends Event>, Handler> handlers=new HashMap<>();
    @SuppressWarnings("unchecked")
    public void handle(Event event) {
        Class<? extends Event> cl=event.getClass();
        while(cl!=null&&!handlers.containsKey(cl)) {
            Class<?> superCl=cl.getSuperclass();
            if (superCl==null||superCl.equals(Object.class)) {
                cl=null;
            }
            else {
                cl=(Class<? extends Event>) superCl;
            }
        }
        if (cl != null) {
            handlers.get(cl).handle(event);
        }
    }
    public void addHandler(Class<? extends Event> eventToHandle, Handler handler) {
        handlers.put(eventToHandle, handler);
    }

package com.stackoverflow.q56754275.multiple_classes;

public class Event {

}
package com.stackoverflow.q56754275.multiple_classes;


public interface Handler {
    void handle(Event event);
}

Как создать обработчик?

package com.stackoverflow.q56754275.multiple_classes;

public class SampleEventHandler implements Handler{

    @Override
    public void handle(Event event) {
        SampleEvent se=(SampleEvent) event;//if this is only for Events of type SampleEvent
        System.out.println(se);
    }

}

Как создать событие?

package com.stackoverflow.q56754275.multiple_classes;

public class SampleEvent extends Event {
    @Override
    public String toString() {
        return "SampleEvent";
    }
}

Как добавитьобработчик контроллера (например, SampleEventHandler для SampleEvent с?

controller.addHandler(SampleEvent.class, new SampleEventHandler());

[ПРИМЕЧАНИЕ]

Возможно выполнение нескольких обработчиков, если вы используете Collection s для обработчиков и перебирать их.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...