我有一个
sealed interface Event
和一个包含列表的域对象。由于 Event 的所有可能实现在编译时都是已知的,因此我可以根据其类来处理每个 Event。问题是我将有许多 Event 的实现,并且我想要一种简单的方法来为新事件添加新的处理程序,而无需修改大量现有代码。
目前,我使用以下方法:
List<Event> events;
List<Handler> handlers;
events.forEach(event -> handlers.forEach(handler -> handler.handle(event)));
public class MealEventHandler implements Handler {
@Override
void handle(Event event) {
if (event instanceof MealEvent mealEvent) {
// logic
}
}
}
但是,我想要一些更具可扩展性的东西,就像这样(但它不能编译):
public interface Handler<T extends Event> {
default void handle(Event event) {
if (event instanceof T e) {
realHandle(e);
}
}
void realHandle(T event);
}
这样,我就可以拥有一个专门处理某种类型事件的处理程序。但我不确定如何修改代码来实现这一点并允许轻松添加新处理程序。如何改进我的设计,使其既类型安全又灵活,以便随着事件类型数量的增长添加新的事件处理程序?
首先,使用
sealed
没有任何意义——它不符合你的需求。 Brian Goetz 的这个回答对于理解正确的用法非常有帮助。
您可以根据事件类使用委托。
public class DelegatingHandler implements Handler<Event> {
private static final NotSupportedEvent NOT_SUPPORTED_EVENT = new NotSupportedEvent();
private final Map<Class<? extends Event>, Handler<? extends Event>> delegates = new HashMap<>();
@Override
public void handle(Event event) {
Class<? extends Event> eventClass = event.getClass();
//handle unsupported type appropriately
//this falls back to no op
@SuppressWarnings("unchecked")
Handler<Event> delegate = (Handler<Event>) delegates.getOrDefault(eventClass, NOT_SUPPORTED_EVENT);
delegate.handle(event);
}
public void registerDelegate(Class<? extends Event> eventClass, Handler<? extends Event> delegate) {
//consider how to handle duplicate keys, depending on the use case
delegates.put(eventClass, delegate);
}
private static final class NotSupportedEvent implements Handler<Event> {
@Override
public void handle(Event event) {
System.out.println(event.getClass().getSimpleName() + ": not supported");
}
}
}
根据事件类,它将找到此类事件的正确处理程序并将实际工作委托给它。如果未注册该事件的处理程序,则默认为无操作。
使用示例:
DelegatingHandler handler = new DelegatingHandler();
handler.registerDelegate(MealEvent.class, new MealEventHandler());