我应该如何在Java中实现消息类的子类型?
我确信这是一个基本的OOP问题——我正在设计一个消息传递系统,其中有几种完全不同的消息格式,但我希望它们都能够放在优先阻塞队列中。我的第一个想法是定义一个我应该如何在Java中实现消息类的子类型?,java,polymorphism,subtyping,Java,Polymorphism,Subtyping,我确信这是一个基本的OOP问题——我正在设计一个消息传递系统,其中有几种完全不同的消息格式,但我希望它们都能够放在优先阻塞队列中。我的第一个想法是定义一个抽象类消息,然后为每个消息类型定义扩展消息的子类。但这意味着,在接收端,消息处理器需要识别子类,以便知道如何处理消息的内容。我所知道的唯一方法是使用.instanceof()或类。但它似乎不太正确 正如Scott Meyers所写 每当你发现自己在写“如果对象是 是T1型的,然后做点什么,但如果是T2型的,那么就做 还有一件事,“打你自己 (他
抽象类消息
,然后为每个消息类型定义扩展消息的子类。但这意味着,在接收端,消息处理器需要识别子类,以便知道如何处理消息的内容。我所知道的唯一方法是使用.instanceof()
或类。
但它似乎不太正确
正如Scott Meyers所写
每当你发现自己在写“如果对象是
是T1型的,然后做点什么,但如果是T2型的,那么就做
还有一件事,“打你自己
(他接着指出,在多态性中,每个子类都应该有相同的方法名和不同的实现。在我的例子中,我看不出我怎么能做到这一点——消息类型本身是完全不相关的。)
为了便于讨论,以下是我的消息类型:
waitForResumeMessage() {
while (true) { // the following will block until a msg arrives
Message msg = inboundMessageQueue.receiveMessage();
msg.process();
- ConsoleMessage,标识ConsoleObject和ObjectState
- CardReaderRequestMessage,不包含任何内容,仅请求“下一张卡”
- CardReaderMessage,包含一个字节[80]卡图像和最后一个卡指示器
- CardPunchMessage,包含一个字节[80]的卡映像
- CardPunchResponseMessage,不包含任何内容,但表示卡映像已复制到穿孔缓冲区
process()
方法。这是我的(简化的)抽象消息和两个子类:
public abstract class Message {
public abstract void process() {
// subclasses of Message implement this
}
public static class ConsoleMessage extends Message {
private int obj;
private int state;
public ConsoleMessage(int x, int y) {
obj = x;
state = y;
}
@Override
public void process() {
// do something with obj and state?
}
public static class CardReaderMessage extends Message {
private byte[] card;
private boolean lastCardIndicator;
public CardReaderMessage(byte[] c, boolean lc) {
card = c;
lastCardIndicator = lc;
}
@Override
public void process() {
// do something with card and lastCardIndicator
}
}
对于所有“入站”消息,每个线程都有一个队列。假设我的线程需要等待来自控制台的消息“恢复”,但同时应该接收和处理其他消息类型:
waitForResumeMessage() {
while (true) { // the following will block until a msg arrives
Message msg = inboundMessageQueue.receiveMessage();
msg.process();
但是现在呢?process()的某些实现将一些数据移动到了某个地方,但最终我需要能够编写:
if // msg was ConsoleMessage "resume" command
return; // .. from waitForResumeMessage()
} // else iterate until another message
}
这基本上意味着找出“msg”属于哪个类
我是不是完全错了?我意识到“等待”在“事件驱动”模型中并不真正合适,但这是一个长期运行的后台工作程序。也许使用process()的想法对于更改引导事件驱动线程的FSM的状态更有用?您的想法很好,确实应该从一个抽象类或一个名为Message的接口开始,这个接口应该是这样的:
public interface Message {
void process();
//some other methods
}
public class MessageType1 implements Message {
@Override
public void process() {
//My special way to process this message
}
}
这样,接收端只需接收消息,即实现您的消息接口,它并不真正关心特定消息的类型,它关心的只是它对流程的响应,因此您可以实现如何在那里处理每个特定消息。您需要的是模板方法。这意味着,您在消息方法中定义了接收端希望使用同一接口调用的方法,但基于实际对象的类型,任何消息类型中的重写方法实际上都会被调用。您不是疯了。这一论点: 任何时候,当你发现自己在写“如果对象是T1类型的,那么做一些事情,但是如果它是T2类型的,那么做一些其他事情”这样的代码时,给自己一记耳光 这只是故事的一个方面。另一方面,保持关注点的分离同样(如果不是更重要的话)重要。一个常见的例子是,您不应该仅仅因为可以在模型中进行多态处理而将表示代码添加到模型中。不幸的是,Java语言在同时实现这两个理想方面没有提供太多帮助
有许多方法可以保持“并行但解耦”的代码。这是一个,就像一个大开关或if块的实例一样。另一个选项是将具体类映射到具体类。除了已经提出的解决方案之外,我想提到的是,您可以在没有任何接口或抽象类的情况下完成 可以创建自己的注释,其中包含可以处理消息对象的信息 在实施时: 您可以相应地对类进行注释 在运行时:
当您从队列中弹出下一个元素时,您可以检查注释并调用能够处理当前实例的实现。但是为了使这成为一个好的设计,这确实假设
process()
是消息的唯一责任,而OP似乎说情况并非如此。@Mark Peters这是真的,但他可以根据需要在界面上声明尽可能多的方法。没错,但很可能不违反单一责任原则或关注点分离,我认为遵循这些原则比避免“切换”设计气味要重要得多。我必须承认,我没有从Animal.talk()到Message.process()进行思维上的飞跃. 真的,我想这就是它所需要做的。我很感激所有关于模板方法、参数多态性甚至注释的反馈——这些对我来说都是相对高级的主题,但我期待着很快掌握设计模式的窍门。这在Java中是什么样子的?基本上是OscarMk上面的答案。啊,你说的“你想要的不是多态性”让我很困惑。奥斯卡的例子肯定是多态性的例子,因为接收端只处理多态性<