Как разобрать входящий поток, когда один кусок определяет интерпретацию другого в Java? - PullRequest
3 голосов
/ 11 февраля 2020

Таким образом, я должен проанализировать заголовок сообщения, где один байт заголовка определяет, как интерпретируется следующий байт. Все интерпретации могут быть представлены как перечисления. Что у меня есть (упрощенно):

enum MsgType { NOP, MSG_A, MSG_B, MSG_C; } // The type of the first byte
enum AInterp { FOO, BAR; }                 // Interpretation of 2nd byte if 1st byte is MSG_A
enum BInterp { ALPHA, BETA, GAMMA; }       // " " " if 1st byte is MSG_B
enum CInterp { ONE, TWO, THREE, FOUR; }    // " " " if 1st byte is MSG_C
AInterp a = null;
BInterp b = null;
CInterp c = null;

У каждого перечисления есть метод enumVal (), который возвращает перечисление для значения байта или ноль, если нет не один, но для этого вопроса мы просто будем использовать valueOf (). Входящий поток содержит заголовок, в котором один фрагмент определяет, как интерпретировать следующий фрагмент. Чтение из ByteBuffer BB:

MsgType m          = MsgType.valueOf(BB.get());
byte    secondByte = BB.get();
switch (m)
{
    case NOP:       /* no options */             break;
    case MSG_A: a = AInterp.valueOf(secondByte); break;
    case MSG_B: b = BInterp.valueOf(secondByte); break;
    case MSG_C: c = CInterp.valueOf(secondByte); break;
    default:        /* no options /*             break;
}

Я знаю, что отсутствуют блоки try / catch, но вы понимаете, в чем дело. Это становится очень громоздким очень быстро. Чтобы запросить значение a, b или c, я должен знать значение m, которое просто не соответствует цели.

Мне бы хотелось иметь возможность каким-то образом создать одну переменную для 2-й байт, и приведите его к типу перечисления, который был бы уместен, что-то вроде:

genericEnum x = null;
MsgType     m = MsgType.valueOf(BB.get());
(typeCastingFrom(m)) x = (typeCastingFrom(m)).valueOf(BB.get())

Так что, я думаю, мне понадобится некоторая схема наследования для перечислений. Но Java этого не позволяет. В конечном итоге я просто сохраню 2-й байт как байт и интерпретирую его, когда мне нужно, на основе m. У кого-нибудь есть более элегантное решение?

1 Ответ

4 голосов
/ 13 февраля 2020

Типы Java enum поддерживают абстракцию через интерфейсы. Таким образом, вы можете объявить

interface Interp {
    String name(); // exists automatically when implemented as enum
    // define common operations
}
enum MsgType { // The type of the first byte
    NOP, MSG_A, MSG_B, MSG_C;
    static MsgType valueOf(byte b) {
        return null;
    }
}
enum AInterp implements Interp {// Interpretation of 2nd byte if 1st byte is MSG_A
    FOO, BAR;
    static AInterp valueOf(byte b) {
        return null;
    }
}
enum BInterp implements Interp {// " " " if 1st byte is MSG_B
    ALPHA, BETA, GAMMA;
    static BInterp valueOf(byte b) {
        return null;
    }
}
enum CInterp implements Interp {// " " " if 1st byte is MSG_C
    ONE, TWO, THREE, FOUR;
    static CInterp valueOf(byte b) {
        return null;
    }
}

Для их единообразной обработки вы можете подготовить структуру данных поиска, например

interface InterpFactory {
    Interp get(byte b);
}
static final Map<MsgType,InterpFactory> KNOWN;
static {
    Map<MsgType,InterpFactory> m = new EnumMap<>(MsgType.class);
    m.put(MsgType.NOP, b -> null);
    m.put(MsgType.MSG_A, AInterp::valueOf);
    m.put(MsgType.MSG_B, BInterp::valueOf);
    m.put(MsgType.MSG_C, CInterp::valueOf);
    KNOWN = Collections.unmodifiableMap(m);
}

, которую можно использовать так же просто, как

MsgType m = MsgType.valueOf(BB.get());
Interp x = KNOWN.get(m).get(BB.get());
.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...