Java中PubNub消息类类型分发的更优实现方案咨询
优化PubNub消息分发:替代冗长instanceof链的方案
哥们,你这个堆满instanceof的判断链确实够头疼的——不仅代码冗余,以后新增消息类型还要挨个加分支,维护成本太高了。结合你需要让子类重载对应消息类型处理方法的需求,给你推荐两种优雅的解决方案:
方案一:类型映射处理器(无需修改Message类)
这种方式用一个Map来存储「消息类型Class」到「对应处理方法」的映射,把原来的硬编码判断转换成动态查找,代码会清爽很多,而且新增消息类型只需要加一行注册代码。
实现步骤:
- 在你的基类中定义一个处理器映射表,并在构造方法中完成绑定:
import java.util.HashMap; import java.util.Map; import java.util.function.Consumer; public abstract class BasePubNubCallback extends SubscribeCallback { private final Map<Class<? extends Message>, Consumer<? extends Message>> messageHandlerMap; public BasePubNubCallback() { messageHandlerMap = new HashMap<>(); // 注册每个消息类型对应的处理方法 registerHandler(DisplayerChanged.class, this::message); registerHandler(DisplayersChanged.class, this::message); registerHandler(NewScreenshotsToRender.class, this::message); registerHandler(RendererChanged.class, this::message); registerHandler(RenderersChanged.class, this::message); registerHandler(ScreenshotRendered.class, this::message); registerHandler(SitesChanged.class, this::message); registerHandler(UsersChanged.class, this::message); } // 通用注册方法,消除重复代码 @SuppressWarnings("unchecked") private <T extends Message> void registerHandler(Class<T> messageClass, Consumer<T> handler) { messageHandlerMap.put(messageClass, (Consumer<? extends Message>) handler); }
- 重写
message方法,直接从映射表中获取处理器执行:
@Override final public void message(PubNub pubnub, PNMessageResult messageResult) { Message message = getMessage(messageResult); Consumer<? extends Message> handler = messageHandlerMap.get(message.getClass()); if (handler != null) { // 这里的强制转换是安全的,因为我们已经通过注册确保了类型匹配 ((Consumer<Message>) handler).accept(message); } else { throw new RuntimeException("Received unexpected message type: " + messageResult); } }
- 保留原来的重载处理方法,子类可以按需重载:
// 子类可重载的处理方法示例 protected void message(DisplayerChanged message) { // 默认实现(可以留空或抛出未实现异常) throw new UnsupportedOperationException("DisplayerChanged handling not implemented"); } protected void message(DisplayersChanged message) { throw new UnsupportedOperationException("DisplayersChanged handling not implemented"); } // ... 其他消息类型的处理方法 }
优势:
- 消除了冗长的
instanceof判断链 - 新增消息类型只需添加一行
registerHandler代码 - 子类依然可以自由重载对应消息类型的处理方法,完全符合你的需求
方案二:访问者模式(需修改Message类)
如果你的Message类及其子类是可修改的,访问者模式是更类型安全的选择——它能在编译期就确保所有消息类型都有对应的处理逻辑,避免漏处理的情况。
实现步骤:
- 定义消息访问者接口:
public interface MessageVisitor { void visit(DisplayerChanged message); void visit(DisplayersChanged message); void visit(NewScreenshotsToRender message); void visit(RendererChanged message); void visit(RenderersChanged message); void visit(ScreenshotRendered message); void visit(SitesChanged message); void visit(UsersChanged message); }
- 在抽象
Message类中添加accept方法:
public abstract class Message { // 原有属性和方法... public abstract void accept(MessageVisitor visitor); }
- 每个消息子类实现
accept方法:
public class DisplayerChanged extends Message { // 原有代码... @Override public void accept(MessageVisitor visitor) { visitor.visit(this); } }
- 让你的基类实现
MessageVisitor接口,并关联到重载的处理方法:
public abstract class BasePubNubCallback extends SubscribeCallback implements MessageVisitor { @Override final public void message(PubNub pubnub, PNMessageResult messageResult) { Message message = getMessage(messageResult); message.accept(this); // 自动分发到对应visit方法 } // 实现Visitor接口,调用对应重载方法 @Override public void visit(DisplayerChanged message) { message(message); } @Override public void visit(DisplayersChanged message) { message(message); } // ... 其他visit方法同理 // 子类可重载的处理方法 protected void message(DisplayerChanged message) { throw new UnsupportedOperationException("DisplayerChanged handling not implemented"); } protected void message(DisplayersChanged message) { throw new UnsupportedOperationException("DisplayersChanged handling not implemented"); } // ... 其他消息类型处理方法 }
优势:
- 完全消除类型转换和
instanceof,类型安全 - 新增消息类型时,编译器会强制你在
MessageVisitor中添加对应visit方法,避免遗漏 - 代码结构更清晰,符合面向对象设计原则
方案选择建议
- 如果无法修改Message类:优先选择「类型映射处理器」方案,灵活且无需改动原有消息结构
- 如果可以修改Message类:优先选择「访问者模式」,类型更安全,可维护性更强
内容的提问来源于stack exchange,提问作者Pablo Fernandez
相关产品推荐
相关产品推荐

