如何在Java中以可扩展的方式处理密封接口的不同实现?

问题描述 投票:0回答:1

我有一个

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

这样,我就可以拥有一个专门处理某种类型事件的处理程序。但我不确定如何修改代码来实现这一点并允许轻松添加新处理程序。如何改进我的设计,使其既类型安全又灵活,以便随着事件类型数量的增长添加新的事件处理程序?

java java-21 java-sealed-type
1个回答
0
投票

首先,使用

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());
© www.soinside.com 2019 - 2024. All rights reserved.