【问题标题】:Java design pattern for event handling with different types?Java设计模式用于不同类型的事件处理?
【发布时间】:2019-06-25 12:37:51
【问题描述】:

我想概括一些代码,它以一种天真的方式实现事件处理。 我有多种类型的事件,它们都共享相同的基本属性以及每种类型独有的属性。 事件以 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}

我正在尝试编写一些通用的东西,它可以让我实现与特定处理分开的通用处理,但是如果我使用一些基础对象BaseEventeventAeventB 扩展自 - 那么,在工厂方法中例如,我丢失了事件的类型,无法将其转发给正确的调用,因此我无法添加 doStuff(EventA a)doStuff(EventB b),因为对象的类型为 BaseEvent

【问题讨论】:

  • 具有 id、baseAttribute1、baseAttribute2、类型的基类。具有事件特定内容的子类。
  • 您的示例不包含“每种类型独有”的属性。
  • 如果你有多个重载的方法handleEvent(BaseEvent),你可以根据使用反射的类型获得java.lang.reflect.Method,并使用事件调用Method

标签: java oop


【解决方案1】:

我必须早些实现类似的东西,这就是我所做的。

1. JSON 转 POJO

您可以使用 jackson json 映射器库将您的多态 json 映射到 pojo。您需要有一个基类,其中包含特定事件类型的派生类。 Jackson inheritance

2。事件处理程序和责任链设计模式

利用责任链设计模式。具有与您的每种事件类型相对应的事件处理程序类。每个事件处理程序都应该有一个安全检查方法,该方法应该根据它是否可以处理该特定类型的事件来返回真/假。这些事件处理程序中的另一种方法应该有代码来处理该事件。如果事件处理程序无法处理该特定事件类型,则应将其传递给下一个事件处理程序。 Chain of responsibility design pattern

另外,您还可以探索观察者设计模式。 Observer design pattern

示例(责任链设计模式)

以下是一个演示相同的简短示例。您可以通过让工厂为您创建链并移动 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>

【讨论】:

  • 使用链的解决方案对于大量处理程序来说资源效率不是很高。考虑Map<Class,AnimalHandler>
  • 同意,我的解决方案更适合一个用例,您需要让多个处理程序作用于一个事件。最好在我的答案中添加一行。
  • 我已添加该解决方案(和其他)作为答案。
  • 我不太喜欢 COR 定义为 catHandler = new CatHandler(dogHandler);
【解决方案2】:

如果您想要一个具有多个方法的处理程序类

您可以简单地使用巨大的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&lt;Class&lt;? extends Event&gt;,Handler&gt; 以查找事件处理程序。

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

如何创建Handler?

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";
    }
}

如何向控制器添加处理程序(例如 SampleEventHandlerSampleEvents ?

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

[注意]

如果您将Collections 用于处理程序并遍历它们,则可以执行多个处理程序。

【讨论】:

  • 这是一个好主意,但我觉得一旦你去 SampleEvent se=(SampleEvent)event ,就会破坏 oop 设计,而且它不是很通用,因为 SampleEventHandler 和 SampleEvent other 之间没有逻辑联系比那一行。我会尝试看看引入泛型是否会增加一些价值
  • 可以在构造函数或工厂方法中自动分配处理程序,如果处理程序。有了这个,你仍然需要强制转换,但你确定类型是正确的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-31
  • 2023-03-26
  • 1970-01-01
相关资源
最近更新 更多