У меня абстрактный класс Interface. Интерфейс имеет метод read, который считывает и анализирует данные, и метод getData, который фактически возвращает проанализированные данные. Каждый интерфейс имеет объект Parser, который выполняет фактический синтаксический анализ. У парсера есть метод parse и геттеры для проанализированных данных.
Классы USBInterface и SerialInterface наследуются от Interface.
Проблема:
Как я могу использовать другой парсер для USBInterface и SerialInterface?
Есть два парсера, USBParser и SerialParser, которые наследуются от Parser.
В моем текущем решении используется ссылка Parser в базовом классе Interface, который инициализируется в конструкторе интерфейса, но я не уверен, что это лучший подход.
class Parser {
public:
Parser() {}
int getData() {
return data;
}
protected:
int data;
};
class USBParser : public Parser {
public:
USBParser() {}
bool parse(uint8_t *usbpacket) {
data = usbpacket[1]; // Do the actual parsing here
return true; // Return true if data is complete
}
};
class SerialParser : public Parser {
public:
SerialParser() {}
bool parse(uint8_t databyte) {
data = databyte; // Do the actual parsing here
return true; // Return true if data is complete
}
};
class Interface {
public:
Interface(Parser &parser) : parser(parser) {}
virtual bool read() = 0;
int getData() {
return parser.getData();
}
protected:
Parser &parser;
};
class USBInterface : public Interface {
public:
USBInterface() : Interface(parser) {}
bool read() {
uint8_t usbpacket[4] = {0x00, 0x01, 0x02, 0x03}; // Read raw data from USB
return parser.parse(usbpacket);
}
private:
USBParser parser;
};
class SerialInterface : public Interface {
public:
SerialInterface() : Interface(parser) {}
bool read() {
uint8_t databyte = 0xFF; // Read raw data from serial port
return parser.parse(databyte);
}
private:
SerialParser parser;
};
int main() {
USBInterface usb;
SerialInterface serial;
if (usb.read())
println(usb.getData());
if (serial.read())
println(serial.getData());
}
Есть ли недостатки в моем подходе или есть способ лучше?
@Serge: спасибо за ваш комментарий. Код, который я опубликовал, упрощен. Цель наследования - сделать абстракцию типа интерфейса. Остальная часть программы не должна заботиться о том, используется ли интерфейс USB или последовательный интерфейс, она просто должна иметь возможность читать данные с интерфейса.





Ваш код мне кажется слишком сложным. Вместо этого вы можете использовать внедрение зависимостей, поскольку класс USBInterface зависит от USBParser, как разумный SerialInterface зависит от SerialParser. Это дает вам больше гибкости. Если у вас есть что-то вроде GenericParser, которое вы хотите использовать с USBInterface или SerialInterface.
class Parser {
public:
Parser() {}
int getData() {
return data;
}
protected:
int data;
};
class USBParser : public Parser {
public:
USBParser() {}
bool parse(uint8_t *usbpacket) {
data = usbpacket[1]; // Do the actual parsing here
return true; // Return true if data is complete
}
};
class SerialParser : public Parser {
public:
SerialParser() {}
bool parse(uint8_t databyte) {
data = databyte; // Do the actual parsing here
return true; // Return true if data is complete
}
};
class Interface {
public:
Interface(Parser &parser) : parser(parser) {}
virtual bool read() = 0;
int getData() {
return parser.getData();
}
protected:
Parser &parser;
};
class USBInterface : public Interface {
public:
USBInterface(Parser &parser) : Interface(parser) {}
bool read() {
uint8_t usbpacket[4] = {0x00, 0x01, 0x02, 0x03}; // Read raw data from USB
return parser.parse(usbpacket);
}
};
class SerialInterface : public Interface {
public:
SerialInterface(Parser &parser) : Interface(parser) {}
bool read() {
uint8_t databyte = 0xFF; // Read raw data from serial port
return parser.parse(databyte);
}
};
int main() {
USBParser usbParse
USBInterface usb(usbParse);
SerialParse serialParse;
SerialInterface serial(serialParse);
// GenericParse parse;
// SerialInterface serial(parse);
if (usb.read())
println(usb.getData());
if (serial.read())
println(serial.getData());
}
Я вижу две непосредственные проблемы с этим подходом: USBParser::parse принимает указатель на массив байтов, а SerialParser::parse принимает один байт. Вдобавок ко всему, внедрение зависимостей не упрощает задачу: USB-интерфейс всегда использует USB-синтаксический анализатор, поэтому нет необходимости полагаться на то, что пользователь предоставит правильный синтаксический анализатор интерфейсу.
Вопрос основан на мнении. ваш подход будет работать. Единственный недостаток в том, что ваш пример не требует наследования. Ваш код выглядит слишком сложным без каких-либо причин, кроме желания добавить наследование.