提示此决定的正确性。
我在Java(服务器)上有一个Web套接字的连接点。它实现了onOpen
,onMessage
,onClose
和onError
方法。
关于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;
}
}
}
}
这样做是真的吗?可以有更优雅的方式处理消息吗?
谢谢。
答案 0 :(得分:1)
创建一个抽象类,其子类覆盖<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/img"
android:text="Text Line"
android:textColor="@color/black" />
<ImageView
android:id="@+id/img"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:adjustViewBounds="true"
android:src="@drawable/signuptop" />
</RelativeLayout>
方法:
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();
}
作为执行参数传递,而不是传递给工厂。