Я уверен, что это основной вопрос ООП - я разрабатываю систему передачи сообщений, в которой есть несколько совершенно разных форматов сообщений, но я хочу, чтобы все они могли быть помещены в PriorityBlockingQueue. Моей первой мыслью было определить abstract class Message
, а затем определить подклассы, расширяющие Message для каждого из типов сообщений. Но это означает, что на принимающей стороне обработчик сообщений должен идентифицировать подкласс, чтобы знать, как обрабатывать содержимое сообщения. И единственный способ, которым я знаю, это делать с .instanceof()
или Class.
, и это как-то не так.
Как пишет Скотт Мейерс,
Каждый раз, когда вы обнаруживаете, что пишете код вида «если объект
типа T1, затем сделать что-то, но если это типа T2, то сделать
что-то еще, "ударить себя.
(Далее он подчеркивает, что в полиморфизме у вас должны быть одинаковые имена методов, имеющие разные реализации для каждого подкласса. Я не понимаю, как я могу заставить эту идею работать в моем случае - сами типы сообщений совершенно не связаны.)
Ради обсуждения, вот мои типы сообщений:
- 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 () более полезна для изменения состояния автомата, который управляет потоком, управляемым событиями?