我相信这是一个基础的面向对象编程问题 -- 我正在设计一个消息传递系统,其中有几种完全不同的消息格式,但我希望它们都能放置在PriorityBlockingQueue上。我的第一个想法是定义一个抽象类Message,然后为每个消息类型定义扩展Message的子类。但这意味着,在接收端,消息处理器需要识别子类以了解如何处理消息的内容。我现在知道的唯一方法是使用.instanceof()或Class。它似乎不合适。
正如Scott Meyers所写,
“每当你发现自己编写的代码形式是"如果对象是类型T1,则执行某些操作,但如果它是类型T2,则执行其他操作",那么就应该打自己。”
(他接着指出,在多态性中,您应该拥有相同的方法名称,对于每个子类,都有不同的实现。我不知道如何让这个思路在我的情况下起作用--消息类型本身完全不相关。)
出于讨论的目的,这里是我的消息类型:
- ConsoleMessage,标识ConsoleObject和ObjectState。 - CardReaderRequestMessage,不包含任何东西,只是请求“下一张卡片” - CardReaderMessage,包含byte[80]卡片图像和Last Card指示符 - CardPunchMessage,包含byte[80]卡片图像 - CardPunchResponseMessage,不包含任何东西,表示卡片图像已复制到打孔缓冲区中
我认为我必须知道我正在处理的消息类型,因此我认为我不应该使用多态的Messages。我应该如何正确地设计这个?
===== 编辑以提出后续问题 =====
我试图找到一种在某些时候不必识别其子类就能使用多态的Message的方法。建议的方法是在每个子类中覆盖一个process()方法。这是我的(简化的)抽象Message和两个子类:
正如Scott Meyers所写,
“每当你发现自己编写的代码形式是"如果对象是类型T1,则执行某些操作,但如果它是类型T2,则执行其他操作",那么就应该打自己。”
(他接着指出,在多态性中,您应该拥有相同的方法名称,对于每个子类,都有不同的实现。我不知道如何让这个思路在我的情况下起作用--消息类型本身完全不相关。)
出于讨论的目的,这里是我的消息类型:
- ConsoleMessage,标识ConsoleObject和ObjectState。 - CardReaderRequestMessage,不包含任何东西,只是请求“下一张卡片” - CardReaderMessage,包含byte[80]卡片图像和Last Card指示符 - CardPunchMessage,包含byte[80]卡片图像 - CardPunchResponseMessage,不包含任何东西,表示卡片图像已复制到打孔缓冲区中
我认为我必须知道我正在处理的消息类型,因此我认为我不应该使用多态的Messages。我应该如何正确地设计这个?
===== 编辑以提出后续问题 =====
我试图找到一种在某些时候不必识别其子类就能使用多态的Message的方法。建议的方法是在每个子类中覆盖一个process()方法。这是我的(简化的)抽象Message和两个子类:
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
}
这基本上意味着找出'class msg'属于哪个类。
我做得对吗?我意识到在“事件驱动”模型中,“等待”并不是很合适,但这是一个长时间运行的后台工作者。也许使用process()函数的想法更有用,用来改变指导事件驱动线程的FSM状态?
process()
是消息的唯一职责,而 OP 似乎在说这不是这种情况。 - Mark Peters