内部非静态类.正确的方法?网络套接字



提示这种决定的正确性。

我在 Java(服务器(上的 Web 套接字有一个连接点。它实现了onOpenonMessageonCloseonError方法。

这是关于onMessage方法的。

我不想用一个开关填充此方法,该开关对于所有可能的消息来说都是巨大的。

做了这种事情(我使用了一个内部非静态类来处理消息(

@ServerEndpoint(value = "/endpoint", configurator = SocketConfigurator.class, encoders = WsEncoder.class, decoders = WsDecoder.class)
public class WsEndpoint {
    private static final CopyOnWriteArrayList<WsUser> wsWebUsers = new CopyOnWriteArrayList<WsUser>();
    public WsEndpoint() {
        LOGGER.info("ENDPOINT CREATED");
    }
    @OnOpen
    public void onOpen(Session session) {
        LOGGER.info("ENDPOINT ONOPEN");
    }
    @OnMessage
    public void onMessage(Session session, WsMessage wsMessage) {
        new WsOnMessage(session, wsMessage);
    }
    @OnClose
    public void onClose(Session session) {
    }
    @OnError
    public void onError(Session session, Throwable ex) {
        LOGGER.error("ENDPOINT ERROR", ex);
    }
    private class WsOnMessage {
        private Session session;
        private WsMessage wsMessage;
        WsOnMessage(Session session, WsMessage wsMessage) {
            this.session = session;
            this.wsMessage = wsMessage;
            execute();
        }
        private void execute() {
            switch (wsMessage.getType()) {
            default:
                LOGGER.info("ENDPOINT UNKNOWN MESSAGE");
                break;
            }
        }
    }
}

这样做是真的吗?有没有更优雅的处理消息的方式?

谢谢。

创建一个抽象类,其中execute方法被其子类覆盖:

public abstract class Command {
  protected final Session session;
  protected final WsMessage message;
  public Command(Session session, WsMessage message) {
    this.session = session;
    this.message = message;
}

  public abstract void execute();
}

创建知道如何将WsMessage映射到相应Command类的命令工厂:

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class CommandFactory {
  private <T extends Command> Class<T> findCommandClass(WsMessage message) {
    // switch on message, or lookup in a Map<WsMessage,Class<? extends Command>>, or,...
    // throw exception if no registered class
    throw new RuntimeException(String.format("No known command for message %s", message));
}
  private <T extends Command> T createInstance(Class<T> clazz, Session session, WsMessage message) {
    try {
        Constructor<T> constructor = clazz.getConstructor(Session.class, WsMessage.class);
        return constructor.newInstance(session, message);
    } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
        throw new RuntimeException(String.format("Could not instantiate  %s", clazz), e);
    }
  }
public Command createCommand(Session session, WsMessage message) {
    Class<Command> commandClass = findCommandClass(message);
    return createInstance(commandClass, session, message);
}
}

WsEndpoint有对工厂的引用:

public class WsEndpoint {
   private CommandFactory factory;
   // if you are required to have a no-arg default constructor and can't use dependency injection:
   public WsEndpoint() {
       this(new MyStandardCommandFactory()); // create an instance of the standard command factory.
   }
   public WsEndpoint(CommandFactory factory) {
       this.factory = Objects.requireNonNull(factory);
   }
   @OnMessage
   public void onMessage(Session session, WsMessage wsMessage) {
        Command command = factory.createCommand(session, wsMessage);
        command.execute();
   }

此模式将允许您通过模拟命令工厂进行测试。

一些想法:

  • 使命令工厂抽象,并使用引发异常的默认实现保护 find 方法。
  • 也许仅将Session作为执行参数传递,而不是传递给工厂。

最新更新