Сейчас они наследуются от одного класса с виртуалами, сделать от разных. Тогда можно иметь больше общих методов в базовых классах. И контейнеры обработчиков разные, тогда можно их мапами
Нет, HciCommand и HciEvent - это два разных базового класса. От HciCommand наследуется ResetCommand, а от HciEvent наследуется ResetCommandCompleteEvent
(если я правильно понял твой комментарий).
Есть также две дополнителных сущности:
* Reply - что-то типа хендла операции, к которому можно приконнектится и прочее (по аналогии с QNetworkReply).
Этот Reply наследуется от QObject и содержит QByteArray как от request (HciCommand) так и от response (HciEvent).
* ReplyHandler - это базовый обработчик с виртуалами которые должны обрабатывать (проверять, что могут это делать) как исходяшие запросы так
и входяшие ответы. Для каджого типа запроса/ответа - свой обработчик, который принимает только свои пакеты.
Т.е. алгоритм такой:
1. Создаем команду (например Reset) и отправляем ее в менеджер (делаем exec(cmd))
2. Менеджер ищет нужный обработчик, который успешно вернет canHandleRequest(cmd). Этот обработчик также будет обрабатывать и response (когда оно придет).
Далее, создается Reply в который засовываем команду (на хранение), а далее засоваваем этот Reply с указателем на текущий обработчик в контейнер (QHash<Reply *. Handler *>).
Это надо для того чтобы потом (когда придет response и сработает
тот-же обработчик) найти Reply.
3. Приходит какой-то response, менеджер перечисляет обработчики и находит тот, который успешно делает canHandleResponse(resp).
Далее, в контейнере (QHash<Reply *. Handler *>) ищется первое совпадение с Handler* и возвращается соответствующий ему Reply.
4. Далее в Reply запихивается response, Reply изымается из контейнера (если надо, это не важно), и финализируется (т.е. емитим сигнал finished и прочее - неважно).
5. В методах конкретных обработчиков для проверки (мой пакет / чужой пакет) просто на сырой QByteArray накладывается соответствующий класс HciCommand/HciEvent.
Например, в ResetReplyHandler это будет проверка ResetCommand(data).isValid() и ResetCommandCompleteEvent(data).isValid() (для canHandleRequest/canHandleResponse соответственно).
Т.е. изначальный мой вопрос был как корректнее можно унифицировать эту проверку, т.к. можно ее также делать с помощью статических методов: ResetCommand::isValid(data) / ResetCommandCompleteEvent::isValid(data) вместо "наложения" класса на QByteArray.
Хотя, также пришлось бы делать и другие методы (для извлечения соотв. свойств из QByteArray) для классов - наследников HciCommand и HciEvent также статическими:
C++ (Qt)
static bool FooCommand::isValid(const QByteArray &data);
static QString FooCommand::name(const QByteArray &data);
static bool BarCommand::isValid(const QByteArray &data);
static Type BarCommand::type(const QByteArray &data);
6. Возможно, что и Reply можно сделать виртуальным, а вместо хранения QByteArray от request/response хранить указатели на конкретные классы от HciCommand / HciEvent ?
C++ (Qt)
class ResetReply : public Reply
{
ResetCommand *request;
ResetCommandCompleteEvent *response;
}
Возможно, имплементацию получения параметров от Request/Response можно сделать напрямую в каждом конкретном Reply вместо HciCommand / HciEvent
(где вместо указателей на HciCommand / HciEvent просто хранить принятые сырые массивы).
C++ (Qt)
class FooReply : public Reply
{
QByteArray request;
QByteArray response;
QString name() const { return response... }; // извлекаем нужный параметр из какого-то там поля из response
}
class BarReply : public Reply
{
QByteArray request;
QByteArray response;
QString type() const { return response... }; // извлекаем нужный параметр из какого-то там поля из response
}
В этом случае когда Reply завершится достаточно просто скастить его к нужному типу (к FooReply или BarReply ) и дернуть желаемые методы получения того или иного параметра..
C++ (Qt)
MyClass::onFooComplete(Reply *reply)
{
// я точно знаю, что слот onFooComplete только для FooReply, поэтому могу кастить
FooReply *reply = qobject_cast<FooReply *>(reply);
QString name = reply->name();
}
вместо того, что есть сейчас:
C++ (Qt)
MyClass::onFooComplete(Reply *reply)
{
// я точно знаю, что слот onFooComplete только для FooReply, поэтому могу наложить FooCompleteEvent на response
QByteArray response = reply->response();
FooCompleteEvent ev(response);
QString name = ev.name();
}
Но все-равно нужно каким-то образом реализовывать методы canHandleRequest/canHandleResponse для обработчиков..
В общем.. такая вот засада.. Много вопросов, а что выбрать в итоге - непонятно.